The UTF-8 BOM was stripped only at the start of the parser stream, but jq feeds all input files into a single parser, so a BOM at the start of the second and later files reached the parser as content and failed with a confusing "Invalid numeric literal" error. Strip it in the file readers instead, at the start of each input file including stdin, and in jv_load_file. This also strips the BOM for raw input, so -R and --rawfile no longer yield a leading U+FEFF, and a BOM at the start of a -f program file or an imported module is now accepted rather than reported as a syntax error. In exchange, "\uFEFF1" | fromjson is now a parse error, since a U+FEFF inside a string is content rather than an encoding marker, and the dedicated "Malformed BOM" error is gone.
2790 lines
56 KiB
Plaintext
2790 lines
56 KiB
Plaintext
# Tests are groups of three lines: program, input, expected output
|
|
# Blank lines and lines starting with # are ignored
|
|
|
|
#
|
|
# Simple value tests to check parser. Input is irrelevant
|
|
#
|
|
|
|
true
|
|
null
|
|
true
|
|
|
|
false
|
|
null
|
|
false
|
|
|
|
null
|
|
42
|
|
null
|
|
|
|
1
|
|
null
|
|
1
|
|
|
|
|
|
-1
|
|
null
|
|
-1
|
|
|
|
# FIXME: much more number testing needed
|
|
|
|
{}
|
|
null
|
|
{}
|
|
|
|
[]
|
|
null
|
|
[]
|
|
|
|
{x:-1},{x:-.},{x:-.|abs}
|
|
1
|
|
{"x":-1}
|
|
{"x":-1}
|
|
{"x":1}
|
|
|
|
# We test escapes by matching them against Unicode codepoints
|
|
# FIXME: more tests needed for weird unicode stuff (e.g. utf16 pairs)
|
|
"Aa\r\n\t\b\f\u03bc"
|
|
null
|
|
"Aa\u000d\u000a\u0009\u0008\u000c\u03bc"
|
|
|
|
.
|
|
"Aa\r\n\t\b\f\u03bc"
|
|
"Aa\u000d\u000a\u0009\u0008\u000c\u03bc"
|
|
|
|
%%FAIL
|
|
"u\vw"
|
|
jq: error: Invalid escape at line 1, column 4 (while parsing '"\v"') at <top-level>, line 1, column 3:
|
|
"u\vw"
|
|
^^
|
|
|
|
"inter\("pol" + "ation")"
|
|
null
|
|
"interpolation"
|
|
|
|
@text,@json,([1,.]|@csv,@tsv),@html,(@uri|.,@urid),@sh,(@base64|.,@base64d)
|
|
"!()<>&'\"\t"
|
|
"!()<>&'\"\t"
|
|
"\"!()<>&'\\\"\\t\""
|
|
"1,\"!()<>&'\"\"\t\""
|
|
"1\t!()<>&'\"\\t"
|
|
"!()<>&'"\t"
|
|
"%21%28%29%3C%3E%26%27%22%09"
|
|
"!()<>&'\"\t"
|
|
"'!()<>&'\\''\"\t'"
|
|
"ISgpPD4mJyIJ"
|
|
"!()<>&'\"\t"
|
|
|
|
# regression test for #436
|
|
@base64
|
|
"foóbar\n"
|
|
"Zm/Ds2Jhcgo="
|
|
|
|
@base64d
|
|
"Zm/Ds2Jhcgo="
|
|
"foóbar\n"
|
|
|
|
@uri
|
|
"\u03bc"
|
|
"%CE%BC"
|
|
|
|
@urid
|
|
"%CE%BC"
|
|
"\u03bc"
|
|
|
|
@html "<b>\(.)</b>"
|
|
"<script>hax</script>"
|
|
"<b><script>hax</script></b>"
|
|
|
|
[.[]|tojson|fromjson]
|
|
["foo", 1, ["a", 1, "b", 2, {"foo":"bar"}]]
|
|
["foo",1,["a",1,"b",2,{"foo":"bar"}]]
|
|
|
|
#
|
|
# Dictionary construction syntax
|
|
#
|
|
|
|
{a: 1}
|
|
null
|
|
{"a":1}
|
|
|
|
{a,b,(.d):.a,e:.b}
|
|
{"a":1, "b":2, "c":3, "d":"c"}
|
|
{"a":1, "b":2, "c":1, "e":2}
|
|
|
|
{"a",b,"a$\(1+1)"}
|
|
{"a":1, "b":2, "c":3, "a$2":4}
|
|
{"a":1, "b":2, "a$2":4}
|
|
|
|
%%FAIL
|
|
{(0):1}
|
|
jq: error: Cannot use number (0) as object key at <top-level>, line 1, column 3:
|
|
{(0):1}
|
|
^
|
|
|
|
%%FAIL
|
|
{1+2:3}
|
|
jq: error: May need parentheses around object key expression at <top-level>, line 1, column 2:
|
|
{1+2:3}
|
|
^^^
|
|
|
|
%%FAIL
|
|
{non_const:., (0):1}
|
|
jq: error: Cannot use number (0) as object key at <top-level>, line 1, column 16:
|
|
{non_const:., (0):1}
|
|
^
|
|
|
|
#
|
|
# Field access, piping
|
|
#
|
|
|
|
.foo
|
|
{"foo": 42, "bar": 43}
|
|
42
|
|
|
|
.foo | .bar
|
|
{"foo": {"bar": 42}, "bar": "badvalue"}
|
|
42
|
|
|
|
.foo.bar
|
|
{"foo": {"bar": 42}, "bar": "badvalue"}
|
|
42
|
|
|
|
.foo_bar
|
|
{"foo_bar": 2}
|
|
2
|
|
|
|
.["foo"].bar
|
|
{"foo": {"bar": 42}, "bar": "badvalue"}
|
|
42
|
|
|
|
."foo"."bar"
|
|
{"foo": {"bar": 20}}
|
|
20
|
|
|
|
.e0, .E1, .E-1, .E+1
|
|
{"e0": 1, "E1": 2, "E": 3}
|
|
1
|
|
2
|
|
2
|
|
4
|
|
|
|
[.[]|.foo?]
|
|
[1,[2],{"foo":3,"bar":4},{},{"foo":5}]
|
|
[3,null,5]
|
|
|
|
[.[]|.foo?.bar?]
|
|
[1,[2],[],{"foo":3},{"foo":{"bar":4}},{}]
|
|
[4,null]
|
|
|
|
[..]
|
|
[1,[[2]],{ "a":[1]}]
|
|
[[1,[[2]],{"a":[1]}],1,[[2]],[2],2,{"a":[1]},[1],1]
|
|
|
|
[.[]|.[]?]
|
|
[1,null,[],[1,[2,[[3]]]],[{}],[{"a":[1,[2]]}]]
|
|
[1,[2,[[3]]],{},{"a":[1,[2]]}]
|
|
|
|
[.[]|.[1:3]?]
|
|
[1,null,true,false,"abcdef",{},{"a":1,"b":2},[],[1,2,3,4,5],[1,2]]
|
|
[null,"bc",[],[2,3],[2]]
|
|
|
|
# chaining/suffix-list, with and without dot
|
|
map(try .a[] catch ., try .a.[] catch ., .a[]?, .a.[]?)
|
|
[{"a": [1,2]}, {"a": 123}]
|
|
[1,2,1,2,1,2,1,2,"Cannot iterate over number (123)","Cannot iterate over number (123)"]
|
|
|
|
# oss-fuzz #66070: objects[] leaks if a non-last element throws an error
|
|
try ["OK", (.[] | error)] catch ["KO", .]
|
|
{"a":["b"],"c":["d"]}
|
|
["KO",["b"]]
|
|
|
|
#
|
|
# Negative array indices
|
|
#
|
|
|
|
try (.foo[-1] = 0) catch .
|
|
null
|
|
"Out of bounds negative array index"
|
|
|
|
try (.foo[-2] = 0) catch .
|
|
null
|
|
"Out of bounds negative array index"
|
|
|
|
.[-1] = 5
|
|
[0,1,2]
|
|
[0,1,5]
|
|
|
|
.[-2] = 5
|
|
[0,1,2]
|
|
[0,5,2]
|
|
|
|
try (.[999999999] = 0) catch .
|
|
null
|
|
"Array index too large"
|
|
|
|
#
|
|
# Multiple outputs, iteration
|
|
#
|
|
|
|
.[]
|
|
[1,2,3]
|
|
1
|
|
2
|
|
3
|
|
|
|
1,1
|
|
[]
|
|
1
|
|
1
|
|
|
|
1,.
|
|
[]
|
|
1
|
|
[]
|
|
|
|
[.]
|
|
[2]
|
|
[[2]]
|
|
|
|
[[2]]
|
|
[3]
|
|
[[2]]
|
|
|
|
[{}]
|
|
[2]
|
|
[{}]
|
|
|
|
[.[]]
|
|
["a"]
|
|
["a"]
|
|
|
|
[(.,1),((.,.[]),(2,3))]
|
|
["a","b"]
|
|
[["a","b"],1,["a","b"],"a","b",2,3]
|
|
|
|
[([5,5][]),.,.[]]
|
|
[1,2,3]
|
|
[5,5,[1,2,3],1,2,3]
|
|
|
|
{x: (1,2)},{x:3} | .x
|
|
null
|
|
1
|
|
2
|
|
3
|
|
|
|
[.[-4,-3,-2,-1,0,1,2,3]]
|
|
[1,2,3]
|
|
[null,1,2,3,1,2,3,null]
|
|
|
|
[range(0;10)]
|
|
null
|
|
[0,1,2,3,4,5,6,7,8,9]
|
|
|
|
[range(0,1;3,4)]
|
|
null
|
|
[0,1,2, 0,1,2,3, 1,2, 1,2,3]
|
|
|
|
[range(0;10;3)]
|
|
null
|
|
[0,3,6,9]
|
|
|
|
[range(0;10;-1)]
|
|
null
|
|
[]
|
|
|
|
[range(0;-5;-1)]
|
|
null
|
|
[0,-1,-2,-3,-4]
|
|
|
|
[range(0;-10;-3)]
|
|
null
|
|
[0,-3,-6,-9]
|
|
|
|
[range(0;10;0)]
|
|
null
|
|
[]
|
|
|
|
[range(0,1;4,5;1,2)]
|
|
null
|
|
[0,1,2,3,0,2, 0,1,2,3,4,0,2,4, 1,2,3,1,3, 1,2,3,4,1,3]
|
|
|
|
try range(.) catch .
|
|
null
|
|
"Range bounds and step must be numeric"
|
|
|
|
try range(0;"") catch .
|
|
null
|
|
"Range bounds and step must be numeric"
|
|
|
|
try range(0;1;[]) catch .
|
|
null
|
|
"Range bounds and step must be numeric"
|
|
|
|
[while(.<100; .*2)]
|
|
1
|
|
[1,2,4,8,16,32,64]
|
|
|
|
[(label $here | .[] | if .>1 then break $here else . end), "hi!"]
|
|
[0,1,2]
|
|
[0,1,"hi!"]
|
|
|
|
[(label $here | .[] | if .>1 then break $here else . end), "hi!"]
|
|
[0,2,1]
|
|
[0,"hi!"]
|
|
|
|
%%FAIL
|
|
. as $foo | break $foo
|
|
jq: error: $*label-foo is not defined at <top-level>, line 1, column 13:
|
|
. as $foo | break $foo
|
|
^^^^^^^^^^
|
|
|
|
[.[]|[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]]
|
|
[1,2,3,4,5]
|
|
[1,2,6,24,120]
|
|
|
|
[label $out | foreach .[] as $item ([3, null]; if .[0] < 1 then break $out else [.[0] -1, $item] end; .[1])]
|
|
[11,22,33,44,55,66,77,88,99]
|
|
[11,22,33]
|
|
|
|
[foreach range(5) as $item (0; $item)]
|
|
null
|
|
[0,1,2,3,4]
|
|
|
|
[foreach .[] as [$i, $j] (0; . + $i - $j)]
|
|
[[2,1], [5,3], [6,4]]
|
|
[1,3,5]
|
|
|
|
[foreach .[] as {a:$a} (0; . + $a; -.)]
|
|
[{"a":1}, {"b":2}, {"a":3, "b":4}]
|
|
[-1, -1, -4]
|
|
|
|
[-foreach -.[] as $x (0; . + $x)]
|
|
[1,2,3]
|
|
[1,3,6]
|
|
|
|
[foreach .[] / .[] as $i (0; . + $i)]
|
|
[1,2]
|
|
[1,3,3.5,4.5]
|
|
|
|
[foreach .[] as $x (0; . + $x) as $x | $x]
|
|
[1,2,3]
|
|
[1,3,6]
|
|
|
|
[limit(3; .[])]
|
|
[11,22,33,44,55,66,77,88,99]
|
|
[11,22,33]
|
|
|
|
[limit(0; error)]
|
|
"badness"
|
|
[]
|
|
|
|
[limit(1; 1, error)]
|
|
"badness"
|
|
[1]
|
|
|
|
try limit(-1; error) catch .
|
|
null
|
|
"limit doesn't support negative count"
|
|
|
|
[skip(3; .[])]
|
|
[1,2,3,4,5,6,7,8,9]
|
|
[4,5,6,7,8,9]
|
|
|
|
[skip(0,2,3,4; .[])]
|
|
[1,2,3]
|
|
[1,2,3,3]
|
|
|
|
[skip(3; .[])]
|
|
[]
|
|
[]
|
|
|
|
try skip(-1; error) catch .
|
|
null
|
|
"skip doesn't support negative count"
|
|
|
|
nth(1; 0,1,error("foo"))
|
|
null
|
|
1
|
|
|
|
[first(range(.)), last(range(.))]
|
|
10
|
|
[0,9]
|
|
|
|
[first(range(.)), last(range(.))]
|
|
0
|
|
[]
|
|
|
|
[nth(0,5,9,10,15; range(.)), try nth(-1; range(.)) catch .]
|
|
10
|
|
[0,5,9,"nth doesn't support negative indices"]
|
|
|
|
# Check that first(g) does not extract more than one value from g
|
|
first(1,error("foo"))
|
|
null
|
|
1
|
|
|
|
#
|
|
# Check that various builtins evaluate all arguments where appropriate,
|
|
# doing cartesian products where appropriate.
|
|
#
|
|
|
|
# Check that limit does work for each value produced by n!
|
|
[limit(5,7; range(9))]
|
|
null
|
|
[0,1,2,3,4,0,1,2,3,4,5,6]
|
|
|
|
# Same check for nth
|
|
[nth(5,7; range(9;0;-1))]
|
|
null
|
|
[4,2]
|
|
|
|
# Same check for range/3
|
|
[range(0,1,2;4,3,2;2,3)]
|
|
null
|
|
[0,2,0,3,0,2,0,0,0,1,3,1,1,1,1,1,2,2,2,2]
|
|
|
|
# Same check for range/1
|
|
[range(3,5)]
|
|
null
|
|
[0,1,2,0,1,2,3,4]
|
|
|
|
# Same check for index/1, rindex/1, indices/1
|
|
[(index(",","|"), rindex(",","|")), indices(",","|")]
|
|
"a,b|c,d,e||f,g,h,|,|,i,j"
|
|
[1,3,22,19,[1,5,7,12,14,16,18,20,22],[3,9,10,17,19]]
|
|
|
|
# Same check for join/1
|
|
join(",","/")
|
|
["a","b","c","d"]
|
|
"a,b,c,d"
|
|
"a/b/c/d"
|
|
|
|
[.[]|join("a")]
|
|
[[],[""],["",""],["","",""]]
|
|
["","","a","aa"]
|
|
|
|
# Same check for flatten/1
|
|
flatten(3,2,1)
|
|
[0, [1], [[2]], [[[3]]]]
|
|
[0,1,2,3]
|
|
[0,1,2,[3]]
|
|
[0,1,[2],[[3]]]
|
|
|
|
|
|
#
|
|
# Slices
|
|
#
|
|
|
|
[.[3:2], .[-5:4], .[:-2], .[-2:], .[3:3][1:], .[10:]]
|
|
[0,1,2,3,4,5,6]
|
|
[[], [2,3], [0,1,2,3,4], [5,6], [], []]
|
|
|
|
[.[3:2], .[-5:4], .[:-2], .[-2:], .[3:3][1:], .[10:]]
|
|
"abcdefghi"
|
|
["","","abcdefg","hi","",""]
|
|
|
|
del(.[2:4],.[0],.[-2:])
|
|
[0,1,2,3,4,5,6,7]
|
|
[1,4,5]
|
|
|
|
.[2:4] = ([], ["a","b"], ["a","b","c"])
|
|
[0,1,2,3,4,5,6,7]
|
|
[0,1,4,5,6,7]
|
|
[0,1,"a","b",4,5,6,7]
|
|
[0,1,"a","b","c",4,5,6,7]
|
|
|
|
# Slices at large offsets (issue #1108)
|
|
#
|
|
# This is written this way because [range(<large number>)] is
|
|
# significantly slower under valgrind than .[<large number>] = value.
|
|
#
|
|
# We range down rather than up so that we have just one realloc.
|
|
reduce range(65540;65536;-1) as $i ([]; .[$i] = $i)|.[65536:]
|
|
null
|
|
[null,65537,65538,65539,65540]
|
|
|
|
#
|
|
# Variables
|
|
#
|
|
|
|
1 as $x | 2 as $y | [$x,$y,$x]
|
|
null
|
|
[1,2,1]
|
|
|
|
[1,2,3][] as $x | [[4,5,6,7][$x]]
|
|
null
|
|
[5]
|
|
[6]
|
|
[7]
|
|
|
|
42 as $x | . | . | . + 432 | $x + 1
|
|
34324
|
|
43
|
|
|
|
1 + 2 as $x | -$x
|
|
null
|
|
-3
|
|
|
|
"x" as $x | "a"+"y" as $y | $x+","+$y
|
|
null
|
|
"x,ay"
|
|
|
|
1 as $x | [$x,$x,$x as $x | $x]
|
|
null
|
|
[1,1,1]
|
|
|
|
[1, {c:3, d:4}] as [$a, {c:$b, b:$c}] | $a, $b, $c
|
|
null
|
|
1
|
|
3
|
|
null
|
|
|
|
. as {as: $kw, "str": $str, ("e"+"x"+"p"): $exp} | [$kw, $str, $exp]
|
|
{"as": 1, "str": 2, "exp": 3}
|
|
[1, 2, 3]
|
|
|
|
.[] as [$a, $b] | [$b, $a]
|
|
[[1], [1, 2, 3]]
|
|
[null, 1]
|
|
[2, 1]
|
|
|
|
. as $i | . as [$i] | $i
|
|
[0]
|
|
0
|
|
|
|
. as [$i] | . as $i | $i
|
|
[0]
|
|
[0]
|
|
|
|
%%FAIL
|
|
. as [] | null
|
|
jq: error: syntax error, unexpected ']', expecting BINDING or '[' or '{' at <top-level>, line 1, column 7:
|
|
. as [] | null
|
|
^
|
|
|
|
%%FAIL
|
|
. as {} | null
|
|
jq: error: syntax error, unexpected '}' at <top-level>, line 1, column 7:
|
|
. as {} | null
|
|
^
|
|
|
|
%%FAIL
|
|
. as $foo | [$foo, $bar]
|
|
jq: error: $bar is not defined at <top-level>, line 1, column 20:
|
|
. as $foo | [$foo, $bar]
|
|
^^^^
|
|
|
|
%%FAIL
|
|
. as {(true):$foo} | $foo
|
|
jq: error: Cannot use boolean (true) as object key at <top-level>, line 1, column 8:
|
|
. as {(true):$foo} | $foo
|
|
^^^^
|
|
|
|
# [.,(.[] | {x:.},.),.,.[]]
|
|
|
|
#
|
|
# Builtin functions
|
|
#
|
|
|
|
1+1
|
|
null
|
|
2
|
|
|
|
1+1
|
|
"wtasdf"
|
|
2.0
|
|
|
|
2-1
|
|
null
|
|
1
|
|
|
|
2-(-1)
|
|
null
|
|
3
|
|
|
|
1e+0+0.001e3
|
|
"I wonder what this will be?"
|
|
20e-1
|
|
|
|
.+4
|
|
15
|
|
19.0
|
|
|
|
.+null
|
|
{"a":42}
|
|
{"a":42}
|
|
|
|
null+.
|
|
null
|
|
null
|
|
|
|
.a+.b
|
|
{"a":42}
|
|
42
|
|
|
|
[1,2,3] + [.]
|
|
null
|
|
[1,2,3,null]
|
|
|
|
{"a":1} + {"b":2} + {"c":3}
|
|
"asdfasdf"
|
|
{"a":1, "b":2, "c":3}
|
|
|
|
"asdf" + "jkl;" + . + . + .
|
|
"some string"
|
|
"asdfjkl;some stringsome stringsome string"
|
|
|
|
"\u0000\u0020\u0000" + .
|
|
"\u0000\u0020\u0000"
|
|
"\u0000 \u0000\u0000 \u0000"
|
|
|
|
42 - .
|
|
11
|
|
31
|
|
|
|
[1,2,3,4,1] - [.,3]
|
|
1
|
|
[2,4]
|
|
|
|
[-1 as $x | 1,$x]
|
|
null
|
|
[1,-1]
|
|
|
|
[10 * 20, 20 / .]
|
|
4
|
|
[200, 5]
|
|
|
|
1 + 2 * 2 + 10 / 2
|
|
null
|
|
10
|
|
|
|
[16 / 4 / 2, 16 / 4 * 2, 16 - 4 - 2, 16 - 4 + 2]
|
|
null
|
|
[2, 8, 10, 14]
|
|
|
|
1e-19 + 1e-20 - 5e-21
|
|
null
|
|
1.05e-19
|
|
|
|
1 / 1e-17
|
|
null
|
|
1e+17
|
|
|
|
9E999999999, 9999999999E999999990, 1E-999999999, 0.000000001E-999999990
|
|
null
|
|
9E+999999999
|
|
9.999999999E+999999999
|
|
1E-999999999
|
|
1E-999999999
|
|
|
|
5E500000000 > 5E-5000000000, 10000E500000000 > 10000E-5000000000
|
|
null
|
|
true
|
|
true
|
|
|
|
# #2825
|
|
(1e999999999, 10e999999999) > (1e-1147483646, 0.1e-1147483646)
|
|
null
|
|
true
|
|
true
|
|
true
|
|
true
|
|
|
|
25 % 7
|
|
null
|
|
4
|
|
|
|
49732 % 472
|
|
null
|
|
172
|
|
|
|
[(infinite, -infinite) % (1, -1, infinite)]
|
|
null
|
|
[0,0,0,0,0,-1]
|
|
|
|
[nan % 1, 1 % nan | isnan]
|
|
null
|
|
[true,true]
|
|
|
|
1 + tonumber + ("10" | tonumber)
|
|
4
|
|
15
|
|
|
|
"123\u0000456" | try tonumber catch .
|
|
null
|
|
"string (\"123\\u0000456\") cannot be parsed as a number"
|
|
|
|
map(toboolean)
|
|
["false","true",false,true]
|
|
[false,true,false,true]
|
|
|
|
.[] | try toboolean catch .
|
|
[null,0,"tru","truee","fals","falsee",[],{}]
|
|
"null (null) cannot be parsed as a boolean"
|
|
"number (0) cannot be parsed as a boolean"
|
|
"string (\"tru\") cannot be parsed as a boolean"
|
|
"string (\"truee\") cannot be parsed as a boolean"
|
|
"string (\"fals\") cannot be parsed as a boolean"
|
|
"string (\"falsee\") cannot be parsed as a boolean"
|
|
"array ([]) cannot be parsed as a boolean"
|
|
"object ({}) cannot be parsed as a boolean"
|
|
|
|
"true\u0000x", "false\u0000" | try toboolean catch .
|
|
null
|
|
"string (\"true\\u0000x\") cannot be parsed as a boolean"
|
|
"string (\"false\\u0000\") cannot be parsed as a boolean"
|
|
|
|
[{"a":42},.object,10,.num,false,true,null,"b",[1,4]] | .[] as $x | [$x == .[]]
|
|
{"object": {"a":42}, "num":10.0}
|
|
[true, true, false, false, false, false, false, false, false]
|
|
[true, true, false, false, false, false, false, false, false]
|
|
[false, false, true, true, false, false, false, false, false]
|
|
[false, false, true, true, false, false, false, false, false]
|
|
[false, false, false, false, true, false, false, false, false]
|
|
[false, false, false, false, false, true, false, false, false]
|
|
[false, false, false, false, false, false, true, false, false]
|
|
[false, false, false, false, false, false, false, true, false]
|
|
[false, false, false, false, false, false, false, false, true ]
|
|
|
|
[.[] | length]
|
|
[[], {}, [1,2], {"a":42}, "asdf", "\u03bc"]
|
|
[0, 0, 2, 1, 4, 1]
|
|
|
|
utf8bytelength
|
|
"asdf\u03bc"
|
|
6
|
|
|
|
[.[] | try utf8bytelength catch .]
|
|
[[], {}, [1,2], 55, true, false]
|
|
["array ([]) only strings have UTF-8 byte length","object ({}) only strings have UTF-8 byte length","array ([1,2]) only strings have UTF-8 byte length","number (55) only strings have UTF-8 byte length","boolean (true) only strings have UTF-8 byte length","boolean (false) only strings have UTF-8 byte length"]
|
|
|
|
|
|
map(keys)
|
|
[{}, {"abcd":1,"abc":2,"abcde":3}, {"x":1, "z": 3, "y":2}]
|
|
[[], ["abc","abcd","abcde"], ["x","y","z"]]
|
|
|
|
[1,2,empty,3,empty,4]
|
|
null
|
|
[1,2,3,4]
|
|
|
|
map(add)
|
|
[[], [1,2,3], ["a","b","c"], [[3],[4,5],[6]], [{"a":1}, {"b":2}, {"a":3}]]
|
|
[null, 6, "abc", [3,4,5,6], {"a":3, "b": 2}]
|
|
|
|
map_values(.+1)
|
|
[0,1,2]
|
|
[1,2,3]
|
|
|
|
[add(null), add(range(range(10))), add(empty), add(10,range(10))]
|
|
null
|
|
[null,120,null,55]
|
|
|
|
# Real-world use case for add(empty)
|
|
.sum = add(.arr[])
|
|
{"arr":[]}
|
|
{"arr":[],"sum":null}
|
|
|
|
add({(.[]):1}) | keys
|
|
["a","a","b","a","d","b","d","a","d"]
|
|
["a","b","d"]
|
|
|
|
#
|
|
# User-defined functions
|
|
# Oh god.
|
|
#
|
|
|
|
def f: . + 1; def g: def g: . + 100; f | g | f; (f | g), g
|
|
3.0
|
|
106.0
|
|
105.0
|
|
|
|
def f: (1000,2000); f
|
|
123412345
|
|
1000
|
|
2000
|
|
|
|
def f(a;b;c;d;e;f): [a+1,b,c,d,e,f]; f(.[0];.[1];.[0];.[0];.[0];.[0])
|
|
[1,2]
|
|
[2,2,1,1,1,1]
|
|
|
|
def f: 1; def g: f, def f: 2; def g: 3; f, def f: g; f, g; def f: 4; [f, def f: g; def g: 5; f, g]+[f,g]
|
|
null
|
|
[4,1,2,3,3,5,4,1,2,3,3]
|
|
|
|
# Test precedence of 'def' vs '|'
|
|
def a: 0; . | a
|
|
null
|
|
0
|
|
|
|
# Many arguments
|
|
def f(a;b;c;d;e;f;g;h;i;j): [j,i,h,g,f,e,d,c,b,a]; f(.[0];.[1];.[2];.[3];.[4];.[5];.[6];.[7];.[8];.[9])
|
|
[0,1,2,3,4,5,6,7,8,9]
|
|
[9,8,7,6,5,4,3,2,1,0]
|
|
|
|
([1,2] + [4,5])
|
|
[1,2,3]
|
|
[1,2,4,5]
|
|
|
|
true
|
|
[1]
|
|
true
|
|
|
|
null,1,null
|
|
"hello"
|
|
null
|
|
1
|
|
null
|
|
|
|
[1,2,3]
|
|
[5,6]
|
|
[1,2,3]
|
|
|
|
[.[]|floor]
|
|
[-1.1,1.1,1.9]
|
|
[-2, 1, 1]
|
|
|
|
[.[]|sqrt]
|
|
[4,9]
|
|
[2,3]
|
|
|
|
(add / length) as $m | map((. - $m) as $d | $d * $d) | add / length | sqrt
|
|
[2,4,4,4,5,5,7,9]
|
|
2
|
|
|
|
# Should write a test that calls the -lm function from C (or bc(1)) to
|
|
# check that they match the corresponding jq functions. However,
|
|
# there's so little template code standing between that it suffices to
|
|
# test a handful of these. The results were checked by eye against
|
|
# bc(1).
|
|
atan * 4 * 1000000|floor / 1000000
|
|
1
|
|
3.141592
|
|
|
|
[(3.141592 / 2) * (range(0;20) / 20)|cos * 1000000|floor / 1000000]
|
|
null
|
|
[1,0.996917,0.987688,0.972369,0.951056,0.923879,0.891006,0.85264,0.809017,0.760406,0.707106,0.649448,0.587785,0.522498,0.45399,0.382683,0.309017,0.233445,0.156434,0.078459]
|
|
|
|
[(3.141592 / 2) * (range(0;20) / 20)|sin * 1000000|floor / 1000000]
|
|
null
|
|
[0,0.078459,0.156434,0.233445,0.309016,0.382683,0.45399,0.522498,0.587785,0.649447,0.707106,0.760405,0.809016,0.85264,0.891006,0.923879,0.951056,0.972369,0.987688,0.996917]
|
|
|
|
|
|
def f(x): x | x; f([.], . + [42])
|
|
[1,2,3]
|
|
[[[1,2,3]]]
|
|
[[1,2,3],42]
|
|
[[1,2,3,42]]
|
|
[1,2,3,42,42]
|
|
|
|
# test multiple function arities and redefinition
|
|
def f: .+1; def g: f; def f: .+100; def f(a):a+.+11; [(g|f(20)), f]
|
|
1
|
|
[33,101]
|
|
|
|
# test closures and lexical scoping
|
|
def id(x):x; 2000 as $x | def f(x):1 as $x | id([$x, x, x]); def g(x): 100 as $x | f($x,$x+x); g($x)
|
|
"more testing"
|
|
[1,100,2100.0,100,2100.0]
|
|
|
|
# test def f($a) syntax
|
|
def x(a;b): a as $a | b as $b | $a + $b; def y($a;$b): $a + $b; def check(a;b): [x(a;b)] == [y(a;b)]; check(.[];.[]*2)
|
|
[1,2,3]
|
|
true
|
|
|
|
# test backtracking through function calls and returns
|
|
# this test is *evil*
|
|
[[20,10][1,0] as $x | def f: (100,200) as $y | def g: [$x + $y, .]; . + $x | g; f[0] | [f][0][1] | f]
|
|
999999999
|
|
[[110.0, 130.0], [210.0, 130.0], [110.0, 230.0], [210.0, 230.0], [120.0, 160.0], [220.0, 160.0], [120.0, 260.0], [220.0, 260.0]]
|
|
|
|
# test recursion
|
|
def fac: if . == 1 then 1 else . * (. - 1 | fac) end; [.[] | fac]
|
|
[1,2,3,4]
|
|
[1,2,6,24]
|
|
|
|
# test stack overflow and reallocation
|
|
# this test is disabled for now, it takes a realllllly long time.
|
|
# def f: if length > 1000 then . else .+[1]|f end; f | length
|
|
# []
|
|
# 1001
|
|
|
|
reduce .[] as $x (0; . + $x)
|
|
[1,2,4]
|
|
7
|
|
|
|
reduce .[] as [$i, {j:$j}] (0; . + $i - $j)
|
|
[[2,{"j":1}], [5,{"j":3}], [6,{"j":4}]]
|
|
5
|
|
|
|
reduce [[1,2,10], [3,4,10]][] as [$i,$j] (0; . + $i * $j)
|
|
null
|
|
14
|
|
|
|
[-reduce -.[] as $x (0; . + $x)]
|
|
[1,2,3]
|
|
[6]
|
|
|
|
[reduce .[] / .[] as $i (0; . + $i)]
|
|
[1,2]
|
|
[4.5]
|
|
|
|
reduce .[] as $x (0; . + $x) as $x | $x
|
|
[1,2,3]
|
|
6
|
|
|
|
# This, while useless, should still compile.
|
|
reduce . as $n (.; .)
|
|
null
|
|
null
|
|
|
|
# Destructuring
|
|
. as {$a, b: [$c, {$d}]} | [$a, $c, $d]
|
|
{"a":1, "b":[2,{"d":3}]}
|
|
[1,2,3]
|
|
|
|
. as {$a, $b:[$c, $d]}| [$a, $b, $c, $d]
|
|
{"a":1, "b":[2,{"d":3}]}
|
|
[1,[2,{"d":3}],2,{"d":3}]
|
|
|
|
# Destructuring with alternation
|
|
.[] | . as {$a, b: [$c, {$d}]} ?// [$a, {$b}, $e] ?// $f | [$a, $b, $c, $d, $e, $f]
|
|
[{"a":1, "b":[2,{"d":3}]}, [4, {"b":5, "c":6}, 7, 8, 9], "foo"]
|
|
[1, null, 2, 3, null, null]
|
|
[4, 5, null, null, 7, null]
|
|
[null, null, null, null, null, "foo"]
|
|
|
|
# Destructuring DUP/POP issues
|
|
.[] | . as {a:$a} ?// {a:$a} ?// {a:$a} | $a
|
|
[[3],[4],[5],6]
|
|
# Runtime error: "jq: Cannot index array with string (\"c\")"
|
|
|
|
.[] as {a:$a} ?// {a:$a} ?// {a:$a} | $a
|
|
[[3],[4],[5],6]
|
|
# Runtime error: "jq: Cannot index array with string (\"c\")"
|
|
|
|
[[3],[4],[5],6][] | . as {a:$a} ?// {a:$a} ?// {a:$a} | $a
|
|
null
|
|
# Runtime error: "jq: Cannot index array with string (\"c\")"
|
|
|
|
[[3],[4],[5],6] | .[] as {a:$a} ?// {a:$a} ?// {a:$a} | $a
|
|
null
|
|
# Runtime error: "jq: Cannot index array with string (\"c\")"
|
|
|
|
.[] | . as {a:$a} ?// {a:$a} ?// $a | $a
|
|
[[3],[4],[5],6]
|
|
[3]
|
|
[4]
|
|
[5]
|
|
6
|
|
|
|
.[] as {a:$a} ?// {a:$a} ?// $a | $a
|
|
[[3],[4],[5],6]
|
|
[3]
|
|
[4]
|
|
[5]
|
|
6
|
|
|
|
[[3],[4],[5],6][] | . as {a:$a} ?// {a:$a} ?// $a | $a
|
|
null
|
|
[3]
|
|
[4]
|
|
[5]
|
|
6
|
|
|
|
[[3],[4],[5],6] | .[] as {a:$a} ?// {a:$a} ?// $a | $a
|
|
null
|
|
[3]
|
|
[4]
|
|
[5]
|
|
6
|
|
|
|
.[] | . as {a:$a} ?// $a ?// {a:$a} | $a
|
|
[[3],[4],[5],6]
|
|
[3]
|
|
[4]
|
|
[5]
|
|
6
|
|
|
|
.[] as {a:$a} ?// $a ?// {a:$a} | $a
|
|
[[3],[4],[5],6]
|
|
[3]
|
|
[4]
|
|
[5]
|
|
6
|
|
|
|
[[3],[4],[5],6][] | . as {a:$a} ?// $a ?// {a:$a} | $a
|
|
null
|
|
[3]
|
|
[4]
|
|
[5]
|
|
6
|
|
|
|
[[3],[4],[5],6] | .[] as {a:$a} ?// $a ?// {a:$a} | $a
|
|
null
|
|
[3]
|
|
[4]
|
|
[5]
|
|
6
|
|
|
|
.[] | . as $a ?// {a:$a} ?// {a:$a} | $a
|
|
[[3],[4],[5],6]
|
|
[3]
|
|
[4]
|
|
[5]
|
|
6
|
|
|
|
.[] as $a ?// {a:$a} ?// {a:$a} | $a
|
|
[[3],[4],[5],6]
|
|
[3]
|
|
[4]
|
|
[5]
|
|
6
|
|
|
|
[[3],[4],[5],6][] | . as $a ?// {a:$a} ?// {a:$a} | $a
|
|
null
|
|
[3]
|
|
[4]
|
|
[5]
|
|
6
|
|
|
|
[[3],[4],[5],6] | .[] as $a ?// {a:$a} ?// {a:$a} | $a
|
|
null
|
|
[3]
|
|
[4]
|
|
[5]
|
|
6
|
|
|
|
. as $dot|any($dot[];not)
|
|
[1,2,3,4,true,false,1,2,3,4,5]
|
|
true
|
|
|
|
. as $dot|any($dot[];not)
|
|
[1,2,3,4,true]
|
|
false
|
|
|
|
. as $dot|all($dot[];.)
|
|
[1,2,3,4,true,false,1,2,3,4,5]
|
|
false
|
|
|
|
. as $dot|all($dot[];.)
|
|
[1,2,3,4,true]
|
|
true
|
|
|
|
# Check short-circuiting
|
|
any(true, error; .)
|
|
"badness"
|
|
true
|
|
|
|
all(false, error; .)
|
|
"badness"
|
|
false
|
|
|
|
any(not)
|
|
[]
|
|
false
|
|
|
|
all(not)
|
|
[]
|
|
true
|
|
|
|
any(not)
|
|
[false]
|
|
true
|
|
|
|
all(not)
|
|
[false]
|
|
true
|
|
|
|
[any,all]
|
|
[]
|
|
[false,true]
|
|
|
|
[any,all]
|
|
[true]
|
|
[true,true]
|
|
|
|
[any,all]
|
|
[false]
|
|
[false,false]
|
|
|
|
[any,all]
|
|
[true,false]
|
|
[true,false]
|
|
|
|
[any,all]
|
|
[null,null,true]
|
|
[true,false]
|
|
|
|
#
|
|
# Paths
|
|
#
|
|
|
|
path(.foo[0,1])
|
|
null
|
|
["foo", 0]
|
|
["foo", 1]
|
|
|
|
path(.[] | select(.>3))
|
|
[1,5,3]
|
|
[1]
|
|
|
|
path(.)
|
|
42
|
|
[]
|
|
|
|
try path(.a | map(select(.b == 0))) catch .
|
|
{"a":[{"b":0}]}
|
|
"Invalid path expression with result [{\"b\":0}]"
|
|
|
|
try path(.a | map(select(.b == 0)) | .[0]) catch .
|
|
{"a":[{"b":0}]}
|
|
"Invalid path expression near attempt to access element 0 of [{\"b\":0}]"
|
|
|
|
try path(.a | map(select(.b == 0)) | .c) catch .
|
|
{"a":[{"b":0}]}
|
|
"Invalid path expression near attempt to access element \"c\" of [{\"b\":0}]"
|
|
|
|
try path(.a | map(select(.b == 0)) | .[]) catch .
|
|
{"a":[{"b":0}]}
|
|
"Invalid path expression near attempt to iterate through [{\"b\":0}]"
|
|
|
|
path(.a[path(.b)[0]])
|
|
{"a":{"b":0}}
|
|
["a","b"]
|
|
|
|
[paths]
|
|
[1,[[],{"a":2}]]
|
|
[[0],[1],[1,0],[1,1],[1,1,"a"]]
|
|
|
|
["foo",1] as $p | getpath($p), setpath($p; 20), delpaths([$p])
|
|
{"bar": 42, "foo": ["a", "b", "c", "d"]}
|
|
"b"
|
|
{"bar": 42, "foo": ["a", 20, "c", "d"]}
|
|
{"bar": 42, "foo": ["a", "c", "d"]}
|
|
|
|
map(getpath([2])), map(setpath([2]; 42)), map(delpaths([[2]]))
|
|
[[0], [0,1], [0,1,2]]
|
|
[null, null, 2]
|
|
[[0,null,42], [0,1,42], [0,1,42]]
|
|
[[0], [0,1], [0,1]]
|
|
|
|
map(delpaths([[0,"foo"]]))
|
|
[[{"foo":2, "x":1}], [{"bar":2}]]
|
|
[[{"x":1}], [{"bar":2}]]
|
|
|
|
["foo",1] as $p | getpath($p), setpath($p; 20), delpaths([$p])
|
|
{"bar":false}
|
|
null
|
|
{"bar":false, "foo": [null, 20]}
|
|
{"bar":false}
|
|
|
|
delpaths([[-200]])
|
|
[1,2,3]
|
|
[1,2,3]
|
|
|
|
try delpaths(0) catch .
|
|
{}
|
|
"Paths must be specified as an array"
|
|
|
|
del(.), del(empty), del((.foo,.bar,.baz) | .[2,3,0]), del(.foo[0], .bar[0], .foo, .baz.bar[0].x)
|
|
{"foo": [0,1,2,3,4], "bar": [0,1]}
|
|
null
|
|
{"foo": [0,1,2,3,4], "bar": [0,1]}
|
|
{"foo": [1,4], "bar": [1]}
|
|
{"bar": [1]}
|
|
|
|
del(.[1], .[-6], .[2], .[-3:9])
|
|
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
[0, 3, 5, 6, 9]
|
|
|
|
del(.[nan])
|
|
[1,2,3]
|
|
[1,2,3]
|
|
|
|
del(.[nan,nan])
|
|
[1,2,3]
|
|
[1,2,3]
|
|
|
|
# negative index
|
|
setpath([-1]; 1)
|
|
[0]
|
|
[1]
|
|
|
|
pick(.a.b.c)
|
|
null
|
|
{"a":{"b":{"c":null}}}
|
|
|
|
pick(first)
|
|
[1,2]
|
|
[1]
|
|
|
|
pick(first|first)
|
|
[[10,20],30]
|
|
[[10]]
|
|
|
|
# negative indices in path expressions (since last/1 is .[-1])
|
|
try pick(last) catch .
|
|
[1,2]
|
|
"Out of bounds negative array index"
|
|
|
|
#
|
|
# Assignment
|
|
#
|
|
.message = "goodbye"
|
|
{"message": "hello"}
|
|
{"message": "goodbye"}
|
|
|
|
.foo = .bar
|
|
{"bar":42}
|
|
{"foo":42, "bar":42}
|
|
|
|
.foo |= .+1
|
|
{"foo": 42}
|
|
{"foo": 43}
|
|
|
|
.[] += 2, .[] *= 2, .[] -= 2, .[] /= 2, .[] %=2
|
|
[1,3,5]
|
|
[3,5,7]
|
|
[2,6,10]
|
|
[-1,1,3]
|
|
[0.5, 1.5, 2.5]
|
|
[1,1,1]
|
|
|
|
[.[] % 7]
|
|
[-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7]
|
|
[0,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,0]
|
|
|
|
.foo += .foo
|
|
{"foo":2}
|
|
{"foo":4}
|
|
|
|
.[0].a |= {"old":., "new":(.+1)}
|
|
[{"a":1,"b":2}]
|
|
[{"a":{"old":1, "new":2},"b":2}]
|
|
|
|
def inc(x): x |= .+1; inc(.[].a)
|
|
[{"a":1,"b":2},{"a":2,"b":4},{"a":7,"b":8}]
|
|
[{"a":2,"b":2},{"a":3,"b":4},{"a":8,"b":8}]
|
|
|
|
# #1358, getpath/1 should work in path expressions
|
|
.[] | try (getpath(["a",0,"b"]) |= 5) catch .
|
|
[null,{"b":0},{"a":0},{"a":null},{"a":[0,1]},{"a":{"b":1}},{"a":[{}]},{"a":[{"c":3}]}]
|
|
{"a":[{"b":5}]}
|
|
{"b":0,"a":[{"b":5}]}
|
|
"Cannot index number with number (0)"
|
|
{"a":[{"b":5}]}
|
|
"Cannot index number with string (\"b\")"
|
|
"Cannot index object with number (0)"
|
|
{"a":[{"b":5}]}
|
|
{"a":[{"c":3,"b":5}]}
|
|
|
|
# #2051, deletion using assigning empty against arrays
|
|
(.[] | select(. >= 2)) |= empty
|
|
[1,5,3,0,7]
|
|
[1,0]
|
|
|
|
.[] |= select(. % 2 == 0)
|
|
[0,1,2,3,4,5]
|
|
[0,2,4]
|
|
|
|
.foo[1,4,2,3] |= empty
|
|
{"foo":[0,1,2,3,4,5]}
|
|
{"foo":[0,5]}
|
|
|
|
.[2][3] = 1
|
|
[4]
|
|
[4, null, [null, null, null, 1]]
|
|
|
|
.foo[2].bar = 1
|
|
{"foo":[11], "bar":42}
|
|
{"foo":[11,null,{"bar":1}], "bar":42}
|
|
|
|
try ((map(select(.a == 1))[].b) = 10) catch .
|
|
[{"a":0},{"a":1}]
|
|
"Invalid path expression near attempt to iterate through [{\"a\":1}]"
|
|
|
|
try ((map(select(.a == 1))[].a) |= .+1) catch .
|
|
[{"a":0},{"a":1}]
|
|
"Invalid path expression near attempt to iterate through [{\"a\":1}]"
|
|
|
|
def x: .[1,2]; x=10
|
|
[0,1,2]
|
|
[0,10,10]
|
|
|
|
try (def x: reverse; x=10) catch .
|
|
[0,1,2]
|
|
"Invalid path expression with result [2,1,0]"
|
|
|
|
.[] = 1
|
|
[1,null,Infinity,-Infinity,NaN,-NaN]
|
|
[1,1,1,1,1,1]
|
|
|
|
#
|
|
# Conditionals
|
|
#
|
|
|
|
[.[] | if .foo then "yep" else "nope" end]
|
|
[{"foo":0},{"foo":1},{"foo":[]},{"foo":true},{"foo":false},{"foo":null},{"foo":"foo"},{}]
|
|
["yep","yep","yep","yep","nope","nope","yep","nope"]
|
|
|
|
[.[] | if .baz then "strange" elif .foo then "yep" else "nope" end]
|
|
[{"foo":0},{"foo":1},{"foo":[]},{"foo":true},{"foo":false},{"foo":null},{"foo":"foo"},{}]
|
|
["yep","yep","yep","yep","nope","nope","yep","nope"]
|
|
|
|
[if 1,null,2 then 3 else 4 end]
|
|
null
|
|
[3,4,3]
|
|
|
|
[if empty then 3 else 4 end]
|
|
null
|
|
[]
|
|
|
|
[if 1 then 3,4 else 5 end]
|
|
null
|
|
[3,4]
|
|
|
|
[if null then 3 else 5,6 end]
|
|
null
|
|
[5,6]
|
|
|
|
[if true then 3 end]
|
|
7
|
|
[3]
|
|
|
|
[if false then 3 end]
|
|
7
|
|
[7]
|
|
|
|
[if false then 3 else . end]
|
|
7
|
|
[7]
|
|
|
|
[if false then 3 elif false then 4 end]
|
|
7
|
|
[7]
|
|
|
|
[if false then 3 elif false then 4 else . end]
|
|
7
|
|
[7]
|
|
|
|
[-if true then 1 else 2 end]
|
|
null
|
|
[-1]
|
|
|
|
{x: if true then 1 else 2 end}
|
|
null
|
|
{"x":1}
|
|
|
|
if true then [.] else . end []
|
|
null
|
|
null
|
|
|
|
[.[] | [.foo[] // .bar]]
|
|
[{"foo":[1,2], "bar": 42}, {"foo":[1], "bar": null}, {"foo":[null,false,3], "bar": 18}, {"foo":[], "bar":42}, {"foo": [null,false,null], "bar": 41}]
|
|
[[1,2], [1], [3], [42], [41]]
|
|
|
|
.[] //= .[0]
|
|
["hello",true,false,[false],null]
|
|
["hello",true,"hello",[false],"hello"]
|
|
|
|
.[] | [.[0] and .[1], .[0] or .[1]]
|
|
[[true,[]], [false,1], [42,null], [null,false]]
|
|
[true,true]
|
|
[false,true]
|
|
[false,true]
|
|
[false,false]
|
|
|
|
[.[] | not]
|
|
[1,0,false,null,true,"hello"]
|
|
[false,false,true,true,false,false]
|
|
|
|
# Check numeric comparison binops
|
|
[10 > 0, 10 > 10, 10 > 20, 10 < 0, 10 < 10, 10 < 20]
|
|
{}
|
|
[true,false,false,false,false,true]
|
|
|
|
[10 >= 0, 10 >= 10, 10 >= 20, 10 <= 0, 10 <= 10, 10 <= 20]
|
|
{}
|
|
[true,true,false,false,true,true]
|
|
|
|
# And some in/equality tests
|
|
[ 10 == 10, 10 != 10, 10 != 11, 10 == 11]
|
|
{}
|
|
[true,false,true,false]
|
|
|
|
["hello" == "hello", "hello" != "hello", "hello" == "world", "hello" != "world" ]
|
|
{}
|
|
[true,false,false,true]
|
|
|
|
[[1,2,3] == [1,2,3], [1,2,3] != [1,2,3], [1,2,3] == [4,5,6], [1,2,3] != [4,5,6]]
|
|
{}
|
|
[true,false,false,true]
|
|
|
|
[{"foo":42} == {"foo":42},{"foo":42} != {"foo":42}, {"foo":42} != {"bar":42}, {"foo":42} == {"bar":42}]
|
|
{}
|
|
[true,false,true,false]
|
|
|
|
# ugly complicated thing
|
|
[{"foo":[1,2,{"bar":18},"world"]} == {"foo":[1,2,{"bar":18},"world"]},{"foo":[1,2,{"bar":18},"world"]} == {"foo":[1,2,{"bar":19},"world"]}]
|
|
{}
|
|
[true,false]
|
|
|
|
# containment operator
|
|
[("foo" | contains("foo")), ("foobar" | contains("foo")), ("foo" | contains("foobar"))]
|
|
{}
|
|
[true, true, false]
|
|
|
|
# containment operator (embedded NULs!)
|
|
[contains(""), contains("\u0000")]
|
|
"\u0000"
|
|
[true, true]
|
|
|
|
[contains(""), contains("a"), contains("ab"), contains("c"), contains("d")]
|
|
"ab\u0000cd"
|
|
[true, true, true, true, true]
|
|
|
|
[contains("cd"), contains("b\u0000"), contains("ab\u0000")]
|
|
"ab\u0000cd"
|
|
[true, true, true]
|
|
|
|
[contains("b\u0000c"), contains("b\u0000cd"), contains("b\u0000cd")]
|
|
"ab\u0000cd"
|
|
[true, true, true]
|
|
|
|
[contains("@"), contains("\u0000@"), contains("\u0000what")]
|
|
"ab\u0000cd"
|
|
[false, false, false]
|
|
|
|
|
|
# Try/catch and general `?` operator
|
|
[.[]|try if . == 0 then error("foo") elif . == 1 then .a elif . == 2 then empty else . end catch .]
|
|
[0,1,2,3]
|
|
["foo","Cannot index number with string (\"a\")",3]
|
|
|
|
[.[]|(.a, .a)?]
|
|
[null,true,{"a":1}]
|
|
[null,null,1,1]
|
|
|
|
[[.[]|[.a,.a]]?]
|
|
[null,true,{"a":1}]
|
|
[]
|
|
|
|
[if error then 1 else 2 end?]
|
|
"foo"
|
|
[]
|
|
|
|
try error(0) // 1
|
|
null
|
|
1
|
|
|
|
# Lex token test #3589, like error(0)? // 1
|
|
error(0) ?// 1
|
|
null
|
|
1
|
|
|
|
1, try error(2), 3
|
|
null
|
|
1
|
|
3
|
|
|
|
1 + try 2 catch 3 + 4
|
|
null
|
|
7
|
|
|
|
[-try .]
|
|
1
|
|
[-1]
|
|
|
|
try -.? catch .
|
|
"foo"
|
|
"string (\"foo\") cannot be negated"
|
|
|
|
{x: try 1, y: try error catch 2, z: if true then 3 end}
|
|
null
|
|
{"x":1,"y":2,"z":3}
|
|
|
|
{x: 1 + 2, y: false or true, z: null // 3}
|
|
null
|
|
{"x":3,"y":true,"z":3}
|
|
|
|
.[] | try error catch .
|
|
[1,null,2]
|
|
1
|
|
null
|
|
2
|
|
|
|
try error("\($__loc__)") catch .
|
|
null
|
|
"{\"file\":\"<top-level>\",\"line\":1}"
|
|
|
|
# string operations
|
|
[.[]|startswith("foo")]
|
|
["fo", "foo", "barfoo", "foobar", "barfoob"]
|
|
[false, true, false, true, false]
|
|
|
|
[.[]|endswith("foo")]
|
|
["fo", "foo", "barfoo", "foobar", "barfoob"]
|
|
[false, true, true, false, false]
|
|
|
|
[.[] | split(", ")]
|
|
["a,b, c, d, e,f",", a,b, c, d, e,f, "]
|
|
[["a,b","c","d","e,f"],["","a,b","c","d","e,f",""]]
|
|
|
|
split("")
|
|
"abc"
|
|
["a","b","c"]
|
|
|
|
[.[]|ltrimstr("foo")]
|
|
["fo", "foo", "barfoo", "foobar", "afoo"]
|
|
["fo","","barfoo","bar","afoo"]
|
|
|
|
[.[]|rtrimstr("foo")]
|
|
["fo", "foo", "barfoo", "foobar", "foob"]
|
|
["fo","","bar","foobar","foob"]
|
|
|
|
[.[]|trimstr("foo")]
|
|
["fo", "foo", "barfoo", "foobarfoo", "foob"]
|
|
["fo","","bar","bar","b"]
|
|
|
|
[.[]|ltrimstr("")]
|
|
["a", "xx", ""]
|
|
["a", "xx", ""]
|
|
|
|
[.[]|rtrimstr("")]
|
|
["a", "xx", ""]
|
|
["a", "xx", ""]
|
|
|
|
[.[]|trimstr("")]
|
|
["a", "xx", ""]
|
|
["a", "xx", ""]
|
|
|
|
[(index(","), rindex(",")), indices(",")]
|
|
"a,bc,def,ghij,klmno"
|
|
[1,13,[1,4,8,13]]
|
|
|
|
[ index("aba"), rindex("aba"), indices("aba") ]
|
|
"xababababax"
|
|
[1,7,[1,3,5,7]]
|
|
|
|
# _strindices is used by indices/1 but is callable
|
|
try _strindices("abc") catch .
|
|
123
|
|
"number (123) cannot be searched, as it is not a string"
|
|
|
|
try _strindices(123) catch .
|
|
"abc"
|
|
"number (123) is not a string"
|
|
|
|
# trim
|
|
# \u000b is vertical tab (\v not supported by json)
|
|
map(trim), map(ltrim), map(rtrim)
|
|
[" \n\t\r\f\u000b", ""," ", "a", " a ", "abc", " abc ", " abc", "abc "]
|
|
["", "", "", "a", "a", "abc", "abc", "abc", "abc"]
|
|
["", "", "", "a", "a ", "abc", "abc ", "abc", "abc "]
|
|
["", "", "", "a", " a", "abc", " abc", " abc", "abc"]
|
|
|
|
trim, ltrim, rtrim
|
|
"\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000abc\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000"
|
|
"abc"
|
|
"abc\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000"
|
|
"\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000abc"
|
|
|
|
try trim catch ., try ltrim catch ., try rtrim catch .
|
|
123
|
|
"trim input must be a string"
|
|
"trim input must be a string"
|
|
"trim input must be a string"
|
|
|
|
indices(1)
|
|
[0,1,1,2,3,4,1,5]
|
|
[1,2,6]
|
|
|
|
indices([1,2])
|
|
[0,1,2,3,1,4,2,5,1,2,6,7]
|
|
[1,8]
|
|
|
|
indices([1,2])
|
|
[1]
|
|
[]
|
|
|
|
indices(", ")
|
|
"a,b, cd,e, fgh, ijkl"
|
|
[3,9,14]
|
|
|
|
index("!")
|
|
"здравствуй мир!"
|
|
14
|
|
|
|
.[:rindex("x")]
|
|
"正xyz"
|
|
"正"
|
|
|
|
indices("o")
|
|
"🇬🇧oo"
|
|
[2,3]
|
|
|
|
indices("o")
|
|
"ƒoo"
|
|
[1,2]
|
|
|
|
[.[]|split(",")]
|
|
["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"]
|
|
[["a"," bc"," def"," ghij"," jklmn"," a","b"," c","d"," e","f"],["a","b","c","d"," e","f","g","h"]]
|
|
|
|
[.[]|split(", ")]
|
|
["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"]
|
|
[["a","bc","def","ghij","jklmn","a,b","c,d","e,f"],["a,b,c,d","e,f,g,h"]]
|
|
|
|
[.[] * 3]
|
|
["a", "ab", "abc"]
|
|
["aaa", "ababab", "abcabcabc"]
|
|
|
|
[.[] * "abc"]
|
|
[-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 3.7, 10.0]
|
|
[null,null,"","","abc","abc","abcabcabc","abcabcabcabcabcabcabcabcabcabc"]
|
|
|
|
[. * (nan,-nan)]
|
|
"abc"
|
|
[null,null]
|
|
|
|
. * 100000 | [.[:10],.[-10:]]
|
|
"abc"
|
|
["abcabcabca","cabcabcabc"]
|
|
|
|
. * 1000000000
|
|
""
|
|
""
|
|
|
|
try (. * 1000000000) catch .
|
|
"abc"
|
|
"Repeat string result too long"
|
|
|
|
[.[] / ","]
|
|
["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"]
|
|
[["a"," bc"," def"," ghij"," jklmn"," a","b"," c","d"," e","f"],["a","b","c","d"," e","f","g","h"]]
|
|
|
|
[.[] / ", "]
|
|
["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"]
|
|
[["a","bc","def","ghij","jklmn","a,b","c,d","e,f"],["a,b,c,d","e,f,g,h"]]
|
|
|
|
map(.[1] as $needle | .[0] | contains($needle))
|
|
[[[],[]], [[1,2,3], [1,2]], [[1,2,3], [3,1]], [[1,2,3], [4]], [[1,2,3], [1,4]]]
|
|
[true, true, true, false, false]
|
|
|
|
map(.[1] as $needle | .[0] | contains($needle))
|
|
[[["foobar", "foobaz"], ["baz", "bar"]], [["foobar", "foobaz"], ["foo"]], [["foobar", "foobaz"], ["blap"]]]
|
|
[true, true, false]
|
|
|
|
[({foo: 12, bar:13} | contains({foo: 12})), ({foo: 12} | contains({})), ({foo: 12, bar:13} | contains({baz:14}))]
|
|
{}
|
|
[true, true, false]
|
|
|
|
{foo: {baz: 12, blap: {bar: 13}}, bar: 14} | contains({bar: 14, foo: {blap: {}}})
|
|
{}
|
|
true
|
|
|
|
{foo: {baz: 12, blap: {bar: 13}}, bar: 14} | contains({bar: 14, foo: {blap: {bar: 14}}})
|
|
{}
|
|
false
|
|
|
|
sort
|
|
[42,[2,5,3,11],10,{"a":42,"b":2},{"a":42},true,2,[2,6],"hello",null,[2,5,6],{"a":[],"b":1},"abc","ab",[3,10],{},false,"abcd",null]
|
|
[null,null,false,true,2,10,42,"ab","abc","abcd","hello",[2,5,3,11],[2,5,6],[2,6],[3,10],{},{"a":42},{"a":42,"b":2},{"a":[],"b":1}]
|
|
|
|
(sort_by(.b) | sort_by(.a)), sort_by(.a, .b), sort_by(.b, .c), group_by(.b), group_by(.a + .b - .c == 2)
|
|
[{"a": 1, "b": 4, "c": 14}, {"a": 4, "b": 1, "c": 3}, {"a": 1, "b": 4, "c": 3}, {"a": 0, "b": 2, "c": 43}]
|
|
[{"a": 0, "b": 2, "c": 43}, {"a": 1, "b": 4, "c": 14}, {"a": 1, "b": 4, "c": 3}, {"a": 4, "b": 1, "c": 3}]
|
|
[{"a": 0, "b": 2, "c": 43}, {"a": 1, "b": 4, "c": 14}, {"a": 1, "b": 4, "c": 3}, {"a": 4, "b": 1, "c": 3}]
|
|
[{"a": 4, "b": 1, "c": 3}, {"a": 0, "b": 2, "c": 43}, {"a": 1, "b": 4, "c": 3}, {"a": 1, "b": 4, "c": 14}]
|
|
[[{"a": 4, "b": 1, "c": 3}], [{"a": 0, "b": 2, "c": 43}], [{"a": 1, "b": 4, "c": 14}, {"a": 1, "b": 4, "c": 3}]]
|
|
[[{"a": 1, "b": 4, "c": 14}, {"a": 0, "b": 2, "c": 43}], [{"a": 4, "b": 1, "c": 3}, {"a": 1, "b": 4, "c": 3}]]
|
|
|
|
unique
|
|
[1,2,5,3,5,3,1,3]
|
|
[1,2,3,5]
|
|
|
|
unique
|
|
[]
|
|
[]
|
|
|
|
[min, max, min_by(.[1]), max_by(.[1]), min_by(.[2]), max_by(.[2])]
|
|
[[4,2,"a"],[3,1,"a"],[2,4,"a"],[1,3,"a"]]
|
|
[[1,3,"a"],[4,2,"a"],[3,1,"a"],[2,4,"a"],[4,2,"a"],[1,3,"a"]]
|
|
|
|
[min,max,min_by(.),max_by(.)]
|
|
[]
|
|
[null,null,null,null]
|
|
|
|
.foo[.baz]
|
|
{"foo":{"bar":4},"baz":"bar"}
|
|
4
|
|
|
|
.[] | .error = "no, it's OK"
|
|
[{"error":true}]
|
|
{"error": "no, it's OK"}
|
|
|
|
[{a:1}] | .[] | .a=999
|
|
null
|
|
{"a": 999}
|
|
|
|
to_entries
|
|
{"a": 1, "b": 2}
|
|
[{"key":"a", "value":1}, {"key":"b", "value":2}]
|
|
|
|
from_entries
|
|
[{"key":"a", "value":1}, {"Key":"b", "Value":2}, {"name":"c", "value":3}, {"Name":"d", "Value":4}]
|
|
{"a": 1, "b": 2, "c": 3, "d": 4}
|
|
|
|
with_entries(.key |= "KEY_" + .)
|
|
{"a": 1, "b": 2}
|
|
{"KEY_a": 1, "KEY_b": 2}
|
|
|
|
map(has("foo"))
|
|
[{"foo": 42}, {}]
|
|
[true, false]
|
|
|
|
map(has(2))
|
|
[[0,1], ["a","b","c"]]
|
|
[false, true]
|
|
|
|
has(nan)
|
|
[0,1,2]
|
|
false
|
|
|
|
keys
|
|
[42,3,35]
|
|
[0,1,2]
|
|
|
|
[][.]
|
|
1000000000000000000
|
|
null
|
|
|
|
map([1,2][0:.])
|
|
[-1, 1, 2, 3, 1000000000000000000]
|
|
[[1], [1], [1,2], [1,2], [1,2]]
|
|
|
|
# Test recursive object merge
|
|
|
|
{"k": {"a": 1, "b": 2}} * .
|
|
{"k": {"a": 0,"c": 3}}
|
|
{"k": {"a": 0, "b": 2, "c": 3}}
|
|
|
|
{"k": {"a": 1, "b": 2}, "hello": {"x": 1}} * .
|
|
{"k": {"a": 0,"c": 3}, "hello": 1}
|
|
{"k": {"a": 0, "b": 2, "c": 3}, "hello": 1}
|
|
|
|
{"k": {"a": 1, "b": 2}, "hello": 1} * .
|
|
{"k": {"a": 0,"c": 3}, "hello": {"x": 1}}
|
|
{"k": {"a": 0, "b": 2, "c": 3}, "hello": {"x": 1}}
|
|
|
|
{"a": {"b": 1}, "c": {"d": 2}, "e": 5} * .
|
|
{"a": {"b": 2}, "c": {"d": 3, "f": 9}}
|
|
{"a": {"b": 2}, "c": {"d": 3, "f": 9}, "e": 5}
|
|
|
|
[.[]|arrays]
|
|
[1,2,"foo",[],[3,[]],{},true,false,null]
|
|
[[],[3,[]]]
|
|
|
|
[.[]|objects]
|
|
[1,2,"foo",[],[3,[]],{},true,false,null]
|
|
[{}]
|
|
|
|
[.[]|iterables]
|
|
[1,2,"foo",[],[3,[]],{},true,false,null]
|
|
[[],[3,[]],{}]
|
|
|
|
[.[]|scalars]
|
|
[1,2,"foo",[],[3,[]],{},true,false,null]
|
|
[1,2,"foo",true,false,null]
|
|
|
|
[.[]|values]
|
|
[1,2,"foo",[],[3,[]],{},true,false,null]
|
|
[1,2,"foo",[],[3,[]],{},true,false]
|
|
|
|
[.[]|booleans]
|
|
[1,2,"foo",[],[3,[]],{},true,false,null]
|
|
[true,false]
|
|
|
|
[.[]|nulls]
|
|
[1,2,"foo",[],[3,[]],{},true,false,null]
|
|
[null]
|
|
|
|
flatten
|
|
[0, [1], [[2]], [[[3]]]]
|
|
[0, 1, 2, 3]
|
|
|
|
flatten(0)
|
|
[0, [1], [[2]], [[[3]]]]
|
|
[0, [1], [[2]], [[[3]]]]
|
|
|
|
flatten(2)
|
|
[0, [1], [[2]], [[[3]]]]
|
|
[0, 1, 2, [3]]
|
|
|
|
flatten(2)
|
|
[0, [1, [2]], [1, [[3], 2]]]
|
|
[0, 1, 2, 1, [3], 2]
|
|
|
|
try flatten(-1) catch .
|
|
[0, [1], [[2]], [[[3]]]]
|
|
"flatten depth must not be negative"
|
|
|
|
transpose
|
|
[[1], [2,3]]
|
|
[[1,2],[null,3]]
|
|
|
|
transpose
|
|
[]
|
|
[]
|
|
|
|
ascii_upcase
|
|
"useful but not for é"
|
|
"USEFUL BUT NOT FOR é"
|
|
|
|
bsearch(0,1,2,3,4)
|
|
[1,2,3]
|
|
-1
|
|
0
|
|
1
|
|
2
|
|
-4
|
|
|
|
bsearch({x:1})
|
|
[{ "x": 0 },{ "x": 1 },{ "x": 2 }]
|
|
1
|
|
|
|
try ["OK", bsearch(0)] catch ["KO",.]
|
|
"aa"
|
|
["KO","string (\"aa\") cannot be searched from"]
|
|
|
|
strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
[2015,2,5,23,51,47,4,63]
|
|
"2015-03-05T23:51:47Z"
|
|
|
|
strftime("%A, %B %d, %Y")
|
|
1435677542.822351
|
|
"Tuesday, June 30, 2015"
|
|
|
|
strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
[2024,2,15]
|
|
"2024-03-15T00:00:00Z"
|
|
|
|
mktime
|
|
[2024,8,21]
|
|
1726876800
|
|
|
|
gmtime
|
|
1425599507
|
|
[2015,2,5,23,51,47,4,63]
|
|
|
|
gmtime[5]
|
|
1425599507.25
|
|
47.25
|
|
|
|
# test invalid tm input
|
|
try strftime("%Y-%m-%dT%H:%M:%SZ") catch .
|
|
["a",1,2,3,4,5,6,7]
|
|
"strftime/1 requires parsed datetime inputs"
|
|
|
|
try strflocaltime("%Y-%m-%dT%H:%M:%SZ") catch .
|
|
["a",1,2,3,4,5,6,7]
|
|
"strflocaltime/1 requires parsed datetime inputs"
|
|
|
|
try mktime catch .
|
|
["a",1,2,3,4,5,6,7]
|
|
"mktime requires parsed datetime inputs"
|
|
|
|
# oss-fuzz #67403: non-string argument with number input fails assert
|
|
try ["OK", strftime([])] catch ["KO", .]
|
|
0
|
|
["KO","strftime/1 requires a string format"]
|
|
|
|
try ["OK", strflocaltime({})] catch ["KO", .]
|
|
0
|
|
["KO","strflocaltime/1 requires a string format"]
|
|
|
|
[strptime("%Y-%m-%dT%H:%M:%SZ")|(.,mktime)]
|
|
"2015-03-05T23:51:47Z"
|
|
[[2015,2,5,23,51,47,4,63],1425599507]
|
|
|
|
# Check day-of-week and day of year computations
|
|
# (should trip an assert if this fails)
|
|
last(range(365 * 67)|("1970-03-01T01:02:03Z"|strptime("%Y-%m-%dT%H:%M:%SZ")|mktime) + (86400 * .)|strftime("%Y-%m-%dT%H:%M:%SZ")|strptime("%Y-%m-%dT%H:%M:%SZ"))
|
|
null
|
|
[2037,1,11,1,2,3,3,41]
|
|
|
|
# fromdateiso8601 accepts the calendar, ordinal and week date forms,
|
|
# in both the extended and the basic representation
|
|
[("2015-03-05T23:51:47Z", "20150305T235147Z", "2015-064T23:51:47Z", "2015064T235147Z", "2015-W10-4T23:51:47Z", "2015W104T235147Z") | fromdateiso8601]
|
|
null
|
|
[1425599507,1425599507,1425599507,1425599507,1425599507,1425599507]
|
|
|
|
# fractional seconds, with either decimal sign
|
|
[("2015-03-05T23:51:47.25Z", "2015-03-05T23:51:47,25Z", "20150305T235147.25Z") | fromdateiso8601]
|
|
null
|
|
[1425599507.25,1425599507.25,1425599507.25]
|
|
|
|
# UTC offsets; an absent offset means UTC
|
|
[("2015-03-06T08:51:47+09:00", "2015-03-06T08:51:47+0900", "2015-03-06T08:51:47+09", "2015-03-05T18:21:47-05:30", "2015-03-05T23:51:47z", "2015-03-05T23:51:47") | fromdateiso8601]
|
|
null
|
|
[1425599507,1425599507,1425599507,1425599507,1425599507,1425599507]
|
|
|
|
# the date and the time may be separated by "T", "t" or a space
|
|
[("2015-03-05t23:51:47Z", "2015-03-05 23:51:47Z") | fromdateiso8601]
|
|
null
|
|
[1425599507,1425599507]
|
|
|
|
# the W, T and Z designators may be written in lower case
|
|
[("2015-w10-4t23:51:47z", "2015w104t235147z", "2015-03-05t23:51:47z") | fromdateiso8601]
|
|
null
|
|
[1425599507,1425599507,1425599507]
|
|
|
|
# expanded years carry a sign and exactly six digits
|
|
[("+012015-03-05T23:51:47Z", "-000001-01-01T00:00:00Z", "+0020150305T235147Z", "+2025-03-05", "+02025-03-05", "+0002025-03-05") | try fromdateiso8601 catch "ERR"]
|
|
null
|
|
[316995119507,-62198755200,1425599507,"ERR","ERR","ERR"]
|
|
|
|
# "24:00:00" is midnight of the following day, at any precision
|
|
[("2015-03-05T24:00:00Z", "2015-03-05T24:00Z", "2015-03-05T24Z") | fromdateiso8601 | todate]
|
|
null
|
|
["2015-03-06T00:00:00Z","2015-03-06T00:00:00Z","2015-03-06T00:00:00Z"]
|
|
|
|
# leap seconds are dropped rather than rejected
|
|
"2015-06-30T23:59:60Z" | fromdateiso8601 | todate
|
|
null
|
|
"2015-06-30T23:59:59Z"
|
|
|
|
# 2015 starts on a Thursday, so it has 53 ISO weeks
|
|
"2015-W53-1T00:00:00Z" | fromdateiso8601 | todate
|
|
null
|
|
"2015-12-28T00:00:00Z"
|
|
|
|
# 2016 is a leap year starting on a Friday: 366 days, but only 52 ISO weeks
|
|
[("2016-366T00:00:00Z", "2016-W52-7T00:00:00Z") | fromdateiso8601 | todate]
|
|
null
|
|
["2016-12-31T00:00:00Z","2017-01-01T00:00:00Z"]
|
|
|
|
# fromdateiso8601 is not limited by the range of a 32-bit time_t (#3276)
|
|
fromdate
|
|
"2038-01-19T03:14:08Z"
|
|
2147483648
|
|
|
|
# the time may drop its seconds, or its minutes and seconds
|
|
[("2015-03-05T23:51Z", "2015-03-05T23Z", "20150305T2351Z", "20150305T23Z") | fromdateiso8601]
|
|
null
|
|
[1425599460,1425596400,1425599460,1425596400]
|
|
|
|
# a decimal fraction belongs to the lowest component present
|
|
[("2015-03-05T23:51:47,5Z", "2015-03-05T23:51,5Z", "2015-03-05T23,5Z") | fromdateiso8601]
|
|
null
|
|
[1425599507.5,1425599490,1425598200]
|
|
|
|
# a date on its own is midnight UTC
|
|
[("2015-03-05", "20150305", "2015-064", "2015064", "2015-W10-4", "2015W104") | fromdateiso8601]
|
|
null
|
|
[1425513600,1425513600,1425513600,1425513600,1425513600,1425513600]
|
|
|
|
# the zone designator belongs to the time, so a bare date cannot carry one
|
|
[("2015-03-05Z", "2015-03-05+09:00", "2015-03-05T") | try fromdateiso8601 catch "ERR"]
|
|
null
|
|
["ERR","ERR","ERR"]
|
|
|
|
# the date must be complete, and a time must not be empty
|
|
[("2015", "2015-03", "2015-W10", "2015-03T00:00:00Z", "T23:51:47Z", "T23:51:47", "23:51:47", "") | try fromdateiso8601 catch "ERR"]
|
|
null
|
|
["ERR","ERR","ERR","ERR","ERR","ERR","ERR","ERR"]
|
|
|
|
# the date and the time must agree on whether separators are used,
|
|
# and "YYYYMM" is ambiguous with "YYMMDD"
|
|
[("2015-03-05T235147Z", "20150305T23:51:47Z", "201503T00:00:00Z", "2015-03-05T2351Z", "20150305T23:51Z", "20150305T23205Z") | try fromdateiso8601 catch "ERR"]
|
|
null
|
|
["ERR","ERR","ERR","ERR","ERR","ERR"]
|
|
|
|
# out-of-range components are rejected
|
|
[("2015-02-30T00:00:00Z", "2015-13-01T00:00:00Z", "2015-00-01T00:00:00Z", "2015-366T00:00:00Z", "2016-W53-1T00:00:00Z", "2015-W10-8T00:00:00Z", "2015-W00-1T00:00:00Z", "2015-03-05T25:00:00Z", "2015-03-05T24:00:01Z", "2015-03-05T24:01Z", "2015-03-05T23:60:00Z", "2015-03-05T23:51:47+24:00", "2015-03-05T23:51:47+09:") | try fromdateiso8601 catch "ERR"]
|
|
null
|
|
["ERR","ERR","ERR","ERR","ERR","ERR","ERR","ERR","ERR","ERR","ERR","ERR","ERR"]
|
|
|
|
# the input must be exactly a datetime: no surrounding whitespace
|
|
[(" 2015-03-05T23:51:47Z", "2015-03-05T23:51:47Z ") | try fromdateiso8601 catch "ERR"]
|
|
null
|
|
["ERR","ERR"]
|
|
|
|
try fromdateiso8601 catch .
|
|
123
|
|
"fromdateiso8601 requires string inputs"
|
|
|
|
try fromdateiso8601 catch .
|
|
"not a date"
|
|
"date \"not a date\" is not a valid ISO 8601 datetime"
|
|
|
|
# module system
|
|
import "a" as foo; import "b" as bar; def fooa: foo::a; [fooa, bar::a, bar::b, foo::a]
|
|
null
|
|
["a","b","c","a"]
|
|
|
|
import "c" as foo; [foo::a, foo::c]
|
|
null
|
|
[0,"acmehbah"]
|
|
|
|
include "c"; [a, c]
|
|
null
|
|
[0,"acmehbah"]
|
|
|
|
import "data" as $e; import "data" as $d; [$d[].this,$e[].that,$d::d[].this,$e::e[].that]|join(";")
|
|
null
|
|
"is a test;is too;is a test;is too"
|
|
|
|
# Regression test for #2000
|
|
import "data" as $a; import "data" as $b; def f: {$a, $b}; f
|
|
null
|
|
{"a":[{"this":"is a test","that":"is too"}],"b":[{"this":"is a test","that":"is too"}]}
|
|
|
|
include "shadow1"; e
|
|
null
|
|
2
|
|
|
|
include "shadow1"; include "shadow2"; e
|
|
null
|
|
3
|
|
|
|
import "shadow1" as f; import "shadow2" as f; import "shadow1" as e; [e::e, f::e]
|
|
null
|
|
[2,3]
|
|
|
|
# A module reached only through another module must be linked before its
|
|
# importers, or dead-code elimination drops the definitions that only the
|
|
# importer's body references (#3597)
|
|
include "deep1"; f
|
|
null
|
|
[1,[21,3],[22,3,1]]
|
|
|
|
# ... including when the shared dependency is pulled in first by an importer
|
|
# whose own definitions end up unused, in either import order
|
|
import "deep2a" as a; import "deep2b" as b; b::f
|
|
null
|
|
[22,3,1]
|
|
|
|
import "deep2b" as b; import "deep2a" as a; b::f
|
|
null
|
|
[22,3,1]
|
|
|
|
%%FAIL
|
|
module (.+1); 0
|
|
jq: error: Module metadata must be constant at <top-level>, line 1, column 8:
|
|
module (.+1); 0
|
|
^^^^^
|
|
|
|
%%FAIL
|
|
module []; 0
|
|
jq: error: Module metadata must be an object at <top-level>, line 1, column 8:
|
|
module []; 0
|
|
^^
|
|
|
|
%%FAIL
|
|
include "a" (.+1); 0
|
|
jq: error: Module metadata must be constant at <top-level>, line 1, column 13:
|
|
include "a" (.+1); 0
|
|
^^^^^
|
|
|
|
%%FAIL
|
|
include "a" []; 0
|
|
jq: error: Module metadata must be an object at <top-level>, line 1, column 13:
|
|
include "a" []; 0
|
|
^^
|
|
|
|
%%FAIL
|
|
include "\ "; 0
|
|
jq: error: Invalid escape at line 1, column 4 (while parsing '"\ "') at <top-level>, line 1, column 10:
|
|
include "\ "; 0
|
|
^^
|
|
|
|
%%FAIL
|
|
include "\(a)"; 0
|
|
jq: error: Import path must be constant at <top-level>, line 1, column 9:
|
|
include "\(a)"; 0
|
|
^^^^^^
|
|
|
|
modulemeta
|
|
"c"
|
|
{"whatever":null,"deps":[{"as":"foo","is_data":false,"relpath":"a"},{"search":"./","as":"d","is_data":false,"relpath":"d"},{"search":"./","as":"d2","is_data":false,"relpath":"d"},{"search":"./../lib/jq","as":"e","is_data":false,"relpath":"e"},{"search":"./../lib/jq","as":"f","is_data":false,"relpath":"f"},{"as":"d","is_data":true,"relpath":"data"}],"defs":["a/0","c/0"]}
|
|
|
|
modulemeta | .deps | length
|
|
"c"
|
|
6
|
|
|
|
modulemeta | .defs | length
|
|
"c"
|
|
2
|
|
|
|
%%FAIL IGNORE MSG
|
|
import "syntaxerror" as e; .
|
|
jq: error: syntax error, unexpected ';', expecting end of file at tests/modules/syntaxerror/syntaxerror.jq, line 1, column 4:
|
|
wat;
|
|
^
|
|
|
|
%%FAIL
|
|
%::wat
|
|
jq: error: syntax error, unexpected '%', expecting end of file at <top-level>, line 1, column 1:
|
|
%::wat
|
|
^
|
|
|
|
import "test_bind_order" as check; check::check
|
|
null
|
|
true
|
|
|
|
try -. catch .
|
|
"very-long-long-long-long-string"
|
|
"string (\"very-long-long-long-long...\") cannot be negated"
|
|
|
|
try (.-.) catch .
|
|
"very-long-long-long-long-string"
|
|
"string (\"very-long-long-long-long...\") and string (\"very-long-long-long-long...\") cannot be subtracted"
|
|
|
|
"x" * range(0; 12; 2) + "☆" * 8 | try -. catch .
|
|
null
|
|
"string (\"☆☆☆☆☆☆☆☆\") cannot be negated"
|
|
"string (\"xx☆☆☆☆☆☆☆☆\") cannot be negated"
|
|
"string (\"xxxx☆☆☆☆☆☆...\") cannot be negated"
|
|
"string (\"xxxxxx☆☆☆☆☆☆...\") cannot be negated"
|
|
"string (\"xxxxxxxx☆☆☆☆☆...\") cannot be negated"
|
|
"string (\"xxxxxxxxxx☆☆☆☆...\") cannot be negated"
|
|
|
|
try (. + "x") catch . == if have_decnum then "number (12345678901234567890123456...) and string (\"x\") cannot be added" else "number (12345678901234568000000000...) and string (\"x\") cannot be added" end
|
|
123456789012345678901234567890
|
|
true
|
|
|
|
join(",")
|
|
["1",2,true,false,3.4]
|
|
"1,2,true,false,3.4"
|
|
|
|
.[] | join(",")
|
|
[[], [null], [null,null], [null,null,null]]
|
|
""
|
|
""
|
|
","
|
|
",,"
|
|
|
|
.[] | join(",")
|
|
[["a",null], [null,"a"]]
|
|
"a,"
|
|
",a"
|
|
|
|
try join(",") catch .
|
|
["1","2",{"a":{"b":{"c":33}}}]
|
|
"string (\"1,2,\") and object ({\"a\":{\"b\":{\"c\":33}}}) cannot be added"
|
|
|
|
try join(",") catch .
|
|
["1","2",[3,4,5]]
|
|
"string (\"1,2,\") and array ([3,4,5]) cannot be added"
|
|
|
|
join("-")
|
|
{"a":"x","b":1,"c":null,"d":false}
|
|
"x-1--false"
|
|
|
|
try join(1) catch .
|
|
["a","b"]
|
|
"string (\"a\") and number (1) cannot be added"
|
|
|
|
{if:0,and:1,or:2,then:3,else:4,elif:5,end:6,as:7,def:8,reduce:9,foreach:10,try:11,catch:12,label:13,import:14,include:15,module:16}
|
|
null
|
|
{"if":0,"and":1,"or":2,"then":3,"else":4,"elif":5,"end":6,"as":7,"def":8,"reduce":9,"foreach":10,"try":11,"catch":12,"label":13,"import":14,"include":15,"module":16}
|
|
|
|
try (1/.) catch .
|
|
0
|
|
"number (1) and number (0) cannot be divided because the divisor is zero"
|
|
|
|
try (1/0) catch .
|
|
0
|
|
"number (1) and number (0) cannot be divided because the divisor is zero"
|
|
|
|
try (0/0) catch .
|
|
0
|
|
"number (0) and number (0) cannot be divided because the divisor is zero"
|
|
|
|
try (1%.) catch .
|
|
0
|
|
"number (1) and number (0) cannot be divided (remainder) because the divisor is zero"
|
|
|
|
try (1%0) catch .
|
|
0
|
|
"number (1) and number (0) cannot be divided (remainder) because the divisor is zero"
|
|
|
|
# Basic numbers tests: integers, powers of two
|
|
[range(-52;52;1)] as $powers | [$powers[]|pow(2;.)|log2|round] == $powers
|
|
null
|
|
true
|
|
|
|
[range(-99/2;99/2;1)] as $orig | [$orig[]|pow(2;.)|log2] as $back | ($orig|keys)[]|. as $k | (($orig|.[$k])-($back|.[$k]))|if . < 0 then . * -1 else . end|select(.>.00005)
|
|
null
|
|
|
|
%%FAIL
|
|
{
|
|
jq: error: syntax error, unexpected end of file at <top-level>, line 1, column 1:
|
|
{
|
|
^
|
|
|
|
%%FAIL
|
|
}
|
|
jq: error: syntax error, unexpected INVALID_CHARACTER, expecting end of file at <top-level>, line 1, column 1:
|
|
}
|
|
^
|
|
|
|
(.[{}] = 0)?
|
|
null
|
|
|
|
INDEX(range(5)|[., "foo\(.)"]; .[0])
|
|
null
|
|
{"0":[0,"foo0"],"1":[1,"foo1"],"2":[2,"foo2"],"3":[3,"foo3"],"4":[4,"foo4"]}
|
|
|
|
JOIN({"0":[0,"abc"],"1":[1,"bcd"],"2":[2,"def"],"3":[3,"efg"],"4":[4,"fgh"]}; .[0]|tostring)
|
|
[[5,"foo"],[3,"bar"],[1,"foobar"]]
|
|
[[[5,"foo"],null],[[3,"bar"],[3,"efg"]],[[1,"foobar"],[1,"bcd"]]]
|
|
|
|
range(5;10)|IN(range(10))
|
|
null
|
|
true
|
|
true
|
|
true
|
|
true
|
|
true
|
|
|
|
range(5;13)|IN(range(0;10;3))
|
|
null
|
|
false
|
|
true
|
|
false
|
|
false
|
|
true
|
|
false
|
|
false
|
|
false
|
|
|
|
range(10;12)|IN(range(10))
|
|
null
|
|
false
|
|
false
|
|
|
|
IN(range(10;20); range(10))
|
|
null
|
|
false
|
|
|
|
IN(range(5;20); range(10))
|
|
null
|
|
true
|
|
|
|
# Regression test for #1347
|
|
(.a as $x | .b) = "b"
|
|
{"a":null,"b":null}
|
|
{"a":null,"b":"b"}
|
|
|
|
# Regression test for #1368
|
|
(.. | select(type == "object" and has("b") and (.b | type) == "array")|.b) |= .[0]
|
|
{"a": {"b": [1, {"b": 3}]}}
|
|
{"a": {"b": 1}}
|
|
|
|
isempty(empty)
|
|
null
|
|
true
|
|
|
|
isempty(range(3))
|
|
null
|
|
false
|
|
|
|
isempty(1,error("foo"))
|
|
null
|
|
false
|
|
|
|
# Regression test for #1815
|
|
index("")
|
|
""
|
|
null
|
|
|
|
# check that dead code removal occurs after builtin it generation
|
|
builtins|length > 10
|
|
null
|
|
true
|
|
|
|
"-1"|IN(builtins[] / "/"|.[1])
|
|
null
|
|
false
|
|
|
|
all(builtins[] / "/"; .[1]|tonumber >= 0)
|
|
null
|
|
true
|
|
|
|
builtins|any(.[:1] == "_")
|
|
null
|
|
false
|
|
|
|
## Test ability to use keywords (uncomment after eval is pushed)
|
|
#(.[] as $kw | "\"{\($kw)} as $\($kw) | $\($kw) | {$\($kw)} | {\($kw):.\($kw)}\""|eval|empty),null
|
|
#["as","def","module","import","include","if","then","else","elif","end","reduce","foreach","and","or","try","catch","label","break","__loc__"]
|
|
#null
|
|
#
|
|
#(.[] as $kw | "\"def f($\($kw)): $\($kw); f(.)\""|eval|empty),null
|
|
#["as","def","module","import","include","if","then","else","elif","end","reduce","foreach","and","or","try","catch","label","break","__loc__"]
|
|
#null
|
|
|
|
|
|
#
|
|
# Tests to cover the new toliteral number functionality
|
|
# For an example see #1652 and other linked issues
|
|
#
|
|
|
|
# We are backward and sanity compatible
|
|
|
|
map(. == 1)
|
|
[1, 1.0, 1.000, 100e-2, 1e+0, 0.0001e4]
|
|
[true, true, true, true, true, true]
|
|
|
|
# When no arithmetic is involved jq should preserve the literal value
|
|
|
|
.[0] | tostring | . == if have_decnum then "13911860366432393" else "13911860366432392" end
|
|
[13911860366432393]
|
|
true
|
|
|
|
.x | tojson | . == if have_decnum then "13911860366432393" else "13911860366432392" end
|
|
{"x":13911860366432393}
|
|
true
|
|
|
|
(13911860366432393 == 13911860366432392) | . == if have_decnum then false else true end
|
|
null
|
|
true
|
|
|
|
|
|
# Applying arithmetic to the value will truncate the result to double
|
|
|
|
. - 10
|
|
13911860366432393
|
|
13911860366432382
|
|
|
|
.[0] - 10
|
|
[13911860366432393]
|
|
13911860366432382
|
|
|
|
.x - 10
|
|
{"x":13911860366432393}
|
|
13911860366432382
|
|
|
|
# Unary negation preserves numerical precision
|
|
-. | tojson == if have_decnum then "-13911860366432393" else "-13911860366432392" end
|
|
13911860366432393
|
|
true
|
|
|
|
-. | tojson == if have_decnum then "0.12345678901234567890123456789" else "0.12345678901234568" end
|
|
-0.12345678901234567890123456789
|
|
true
|
|
|
|
[1E+1000,-1E+1000 | tojson] == if have_decnum then ["1E+1000","-1E+1000"] else ["1.7976931348623157e+308","-1.7976931348623157e+308"] end
|
|
null
|
|
true
|
|
|
|
. |= try . catch .
|
|
1
|
|
1
|
|
|
|
# decnum to double conversion
|
|
.[] as $n | $n+0 | [., tostring, . == $n]
|
|
[-9007199254740993, -9007199254740992, 9007199254740992, 9007199254740993, 13911860366432393]
|
|
[-9007199254740992,"-9007199254740992",true]
|
|
[-9007199254740992,"-9007199254740992",true]
|
|
[9007199254740992,"9007199254740992",true]
|
|
[9007199254740992,"9007199254740992",true]
|
|
[13911860366432392,"13911860366432392",true]
|
|
|
|
# abs, fabs, length
|
|
abs
|
|
"abc"
|
|
"abc"
|
|
|
|
map(abs)
|
|
[-0, 0, -10, -1.1]
|
|
[0,0,10,1.1]
|
|
|
|
map(fabs)
|
|
[-0, 0, -10, -1.1]
|
|
[0,0,10,1.1]
|
|
|
|
map(abs == length) | unique
|
|
[-10, -1.1, -1e-1, 1000000000000000002]
|
|
[true]
|
|
|
|
# The following is NOT prescriptive:
|
|
map(abs)
|
|
[0.1,1000000000000000002]
|
|
[1e-1, 1000000000000000002]
|
|
|
|
[1E+1000,-1E+1000 | abs | tojson] | unique == if have_decnum then ["1E+1000"] else ["1.7976931348623157e+308"] end
|
|
null
|
|
true
|
|
|
|
[1E+1000,-1E+1000 | length | tojson] | unique == if have_decnum then ["1E+1000"] else ["1.7976931348623157e+308"] end
|
|
null
|
|
true
|
|
|
|
# Using a keyword as variable/label name
|
|
|
|
123 as $label | $label
|
|
null
|
|
123
|
|
|
|
[ label $if | range(10) | ., (select(. == 5) | break $if) ]
|
|
null
|
|
[0,1,2,3,4,5]
|
|
|
|
reduce .[] as $then (4 as $else | $else; . as $elif | . + $then * $elif)
|
|
[1,2,3]
|
|
96
|
|
|
|
1 as $foreach | 2 as $and | 3 as $or | { $foreach, $and, $or, a }
|
|
{"a":4,"b":5}
|
|
{"foreach":1,"and":2,"or":3,"a":4}
|
|
|
|
[ foreach .[] as $try (1 as $catch | $catch - 1; . + $try; .) ]
|
|
[10,9,8,7]
|
|
[10,19,27,34]
|
|
|
|
|
|
# Object construction
|
|
|
|
{ a, $__loc__, c }
|
|
{"a":[1,2,3],"b":"foo","c":{"hi":"hey"}}
|
|
{"a":[1,2,3],"__loc__":{"file":"<top-level>","line":1},"c":{"hi":"hey"}}
|
|
|
|
1 as $x | "2" as $y | "3" as $z | { $x, as, $y: 4, ($z): 5, if: 6, foo: 7 }
|
|
{"as":8}
|
|
{"x":1,"as":8,"2":4,"3":5,"if":6,"foo":7}
|
|
|
|
|
|
# nan is parsed as a valid NaN value from JSON
|
|
|
|
fromjson | isnan
|
|
"nan"
|
|
true
|
|
|
|
tojson | fromjson
|
|
{"a":nan}
|
|
{"a":null}
|
|
|
|
# NaN with payload is not parsed
|
|
.[] | try (fromjson | isnan) catch .
|
|
["NaN","-NaN","NaN1","NaN10","NaN100","NaN1000","NaN10000","NaN100000"]
|
|
true
|
|
true
|
|
"Invalid numeric literal at EOF at line 1, column 4 (while parsing 'NaN1')"
|
|
"Invalid numeric literal at EOF at line 1, column 5 (while parsing 'NaN10')"
|
|
"Invalid numeric literal at EOF at line 1, column 6 (while parsing 'NaN100')"
|
|
"Invalid numeric literal at EOF at line 1, column 7 (while parsing 'NaN1000')"
|
|
"Invalid numeric literal at EOF at line 1, column 8 (while parsing 'NaN10000')"
|
|
"Invalid numeric literal at EOF at line 1, column 9 (while parsing 'NaN100000')"
|
|
|
|
# calling input/0, or debug/0 in a test doesn't crash jq
|
|
|
|
try input catch .
|
|
null
|
|
"break"
|
|
|
|
debug
|
|
1
|
|
1
|
|
|
|
# try/catch catches more than it should #1859
|
|
"foo" | try ((try . catch "caught too much") | error) catch "caught just right"
|
|
null
|
|
"caught just right"
|
|
|
|
.[]|(try (if .=="hi" then . else error end) catch empty) | "\(.) there!"
|
|
["hi","ho"]
|
|
"hi there!"
|
|
|
|
try (["hi","ho"]|.[]|(try . catch (if .=="ho" then "BROKEN"|error else empty end)) | if .=="ho" then error else "\(.) there!" end) catch "caught outside \(.)"
|
|
null
|
|
"hi there!"
|
|
"caught outside ho"
|
|
|
|
.[]|(try . catch (if .=="ho" then "BROKEN"|error else empty end)) | if .=="ho" then error else "\(.) there!" end
|
|
["hi","ho"]
|
|
"hi there!"
|
|
|
|
try (try error catch "inner catch \(.)") catch "outer catch \(.)"
|
|
"foo"
|
|
"inner catch foo"
|
|
|
|
try ((try error catch "inner catch \(.)")|error) catch "outer catch \(.)"
|
|
"foo"
|
|
"outer catch inner catch foo"
|
|
|
|
# Also #1859, but from #1885
|
|
first(.?,.?)
|
|
null
|
|
null
|
|
|
|
# Also #1859, but from #2140
|
|
{foo: "bar"} | .foo |= .?
|
|
null
|
|
{"foo": "bar"}
|
|
|
|
# Also #1859, but from #2220
|
|
. |= try 2
|
|
1
|
|
2
|
|
|
|
. |= try 2 catch 3
|
|
1
|
|
2
|
|
|
|
.[] |= try tonumber
|
|
["1", "2a", "3", " 4", "5 ", "6.7", ".89", "-876", "+5.43", 21]
|
|
[1, 3, 6.7, 0.89, -876, 5.43, 21]
|
|
|
|
# Also 1859, but from 2073
|
|
any(keys[]|tostring?;true)
|
|
{"a":"1","b":"2","c":"3"}
|
|
true
|
|
|
|
|
|
# explode/implode
|
|
# test replacement character (65533) for outside codepoint range and 0xd800 (55296) - 0xdfff (57343) utf16 surrogate pair range
|
|
# 1.1 and 1.9 to test round down of non-ints
|
|
implode|explode
|
|
[-1,0,1,2,3,1114111,1114112,55295,55296,57343,57344,1.1,1.9]
|
|
[65533,0,1,2,3,1114111,65533,55295,65533,65533,57344,1,1]
|
|
|
|
map(try implode catch .)
|
|
[123,["a"],[nan]]
|
|
["implode input must be an array","string (\"a\") can't be imploded, unicode codepoint needs to be numeric","number (null) can't be imploded, unicode codepoint needs to be numeric"]
|
|
|
|
try 0[implode] catch .
|
|
[]
|
|
"Cannot index number with string (\"\")"
|
|
|
|
# walk
|
|
walk(.)
|
|
{"x":0}
|
|
{"x":0}
|
|
|
|
walk(1)
|
|
{"x":0}
|
|
1
|
|
|
|
# The following is a regression test, not a requirement:
|
|
[walk(.,1)]
|
|
{"x":0}
|
|
[{"x":0},1]
|
|
|
|
# Issue #2584
|
|
walk(select(IN({}, []) | not))
|
|
{"a":1,"b":[]}
|
|
{"a":1}
|
|
|
|
# #2815
|
|
[range(10)] | .[1.2:3.5]
|
|
null
|
|
[1,2,3]
|
|
|
|
[range(10)] | .[1.5:3.5]
|
|
null
|
|
[1,2,3]
|
|
|
|
[range(10)] | .[1.7:3.5]
|
|
null
|
|
[1,2,3]
|
|
|
|
[range(10)] | .[1.7:4294967295]
|
|
null
|
|
[1,2,3,4,5,6,7,8,9]
|
|
|
|
[range(10)] | .[1.7:-4294967296]
|
|
null
|
|
[]
|
|
|
|
[[range(10)] | .[1.1,1.5,1.7]]
|
|
null
|
|
[1,1,1]
|
|
|
|
[range(5)] | .[1.1] = 5
|
|
null
|
|
[0,5,2,3,4]
|
|
|
|
[range(3)] | .[nan:1]
|
|
null
|
|
[0]
|
|
|
|
[range(3)] | .[1:nan]
|
|
null
|
|
[1,2]
|
|
|
|
[range(3)] | .[nan]
|
|
null
|
|
null
|
|
|
|
try ([range(3)] | .[nan] = 9) catch .
|
|
null
|
|
"Cannot set array element at NaN index"
|
|
|
|
try ("foobar" | .[1.5:3.5] = "xyz") catch .
|
|
null
|
|
"Cannot update string slices"
|
|
|
|
try ([range(10)] | .[1.5:3.5] = ["xyz"]) catch .
|
|
null
|
|
[0,"xyz",4,5,6,7,8,9]
|
|
|
|
try ("foobar" | .[1.5]) catch .
|
|
null
|
|
"Cannot index string with number (1.5)"
|
|
|
|
|
|
# setpath/2 does not leak the input after an invalid get #2970
|
|
|
|
try ["ok", setpath([1]; 1)] catch ["ko", .]
|
|
{"hi":"hello"}
|
|
["ko","Cannot index object with number (1)"]
|
|
|
|
try fromjson catch .
|
|
"{'a': 123}"
|
|
"Invalid string literal; expected \", but got ' at line 1, column 5 (while parsing '{'a': 123}')"
|
|
|
|
# ltrimstr/1 rtrimstr/1 don't leak on invalid input #2977
|
|
|
|
try ltrimstr(1) catch "x", try rtrimstr(1) catch "x" | "ok"
|
|
"hi"
|
|
"ok"
|
|
"ok"
|
|
|
|
try ltrimstr("x") catch "x", try rtrimstr("x") catch "x" | "ok"
|
|
{"hey":[]}
|
|
"ok"
|
|
"ok"
|
|
|
|
# ltrimstr/1 and rtrimstr/1 return an error for non-strings. #2969
|
|
|
|
.[] as [$x, $y] | try ["ok", ($x | ltrimstr($y))] catch ["ko", .]
|
|
[["hi",1],[1,"hi"],["hi","hi"],[1,1]]
|
|
["ko","startswith() requires string inputs"]
|
|
["ko","startswith() requires string inputs"]
|
|
["ok",""]
|
|
["ko","startswith() requires string inputs"]
|
|
|
|
.[] as [$x, $y] | try ["ok", ($x | rtrimstr($y))] catch ["ko", .]
|
|
[["hi",1],[1,"hi"],["hi","hi"],[1,1]]
|
|
["ko","endswith() requires string inputs"]
|
|
["ko","endswith() requires string inputs"]
|
|
["ok",""]
|
|
["ko","endswith() requires string inputs"]
|
|
|
|
|
|
# oss-fuzz #66061: setpath/2 leaks when indexing array with array
|
|
|
|
try ["OK", setpath([[1]]; 1)] catch ["KO", .]
|
|
[]
|
|
["KO","Cannot update field at array index of array"]
|
|
|
|
# regression test for #3227 (reduce)
|
|
[] | reduce .[] as $x (0, 1; .)
|
|
null
|
|
0
|
|
1
|
|
|
|
# regression test for #3227 (foreach)
|
|
foreach .[] as $x (0, 1; . + $x)
|
|
[1, 2]
|
|
1
|
|
3
|
|
2
|
|
4
|
|
|
|
# regression test for CVE-2025-49014 (use of fmt after free)
|
|
# tests with both empty string literal and empty string created by function
|
|
# as they seems to behave reference wise differently.
|
|
strflocaltime("" | ., @uri)
|
|
0
|
|
""
|
|
""
|
|
|
|
# regression tests for #3413
|
|
# upper range bounds should be in sync with the constants defined at
|
|
# src/jv_parse.c:#define MAX_PARSING_DEPTH (N)
|
|
# src/jv_print.c:#define MAX_PRINT_DEPTH (N)
|
|
# (N-1)
|
|
reduce range(9999) as $_ ([];[.]) | tojson | fromjson | flatten
|
|
null
|
|
[]
|
|
|
|
# (N)
|
|
reduce range(10000) as $_ ([];[.]) | tojson | try (fromjson) catch . | (contains("<skipped: too deep>") | not) and contains("Exceeds depth limit for parsing")
|
|
null
|
|
true
|
|
|
|
# (N+1)
|
|
reduce range(10001) as $_ ([];[.]) | tojson | contains("<skipped: too deep>")
|
|
null
|
|
true
|
|
|
|
# regression test for CVE-2026-33947
|
|
setpath([range(10000) | 0]; 0) | flatten
|
|
null
|
|
[0]
|
|
|
|
try setpath([range(10001) | 0]; 0) catch .
|
|
null
|
|
"Path too deep"
|
|
|
|
getpath([range(10000) | 0])
|
|
null
|
|
null
|
|
|
|
try getpath([range(10001) | 0]) catch .
|
|
null
|
|
"Path too deep"
|
|
|
|
delpaths([[range(10000) | 0]])
|
|
null
|
|
null
|
|
|
|
try delpaths([[range(10001) | 0]]) catch .
|
|
null
|
|
"Path too deep"
|
|
|
|
# regression test for CVE-2026-40612
|
|
reduce range(10000) as $_ ([]; [.]) | contains([[]])
|
|
null
|
|
true
|
|
|
|
try (reduce range(10001) as $_ ([]; [.]) as $x | $x | contains($x)) catch .
|
|
null
|
|
"Containment check too deep"
|
|
|
|
# regression test for CVE-2026-43896
|
|
reduce range(10000) as $_ ({}; {a: .}) as $x | $x * $x | length
|
|
null
|
|
1
|
|
|
|
try (reduce range(10001) as $_ ({}; {a: .}) as $x | $x * $x) catch .
|
|
null
|
|
"Object merge too deep"
|
|
|
|
# regression test for deep structural equality recursion
|
|
try ((reduce range(10001) as $_ ([]; [.])) as $x | (reduce range(10001) as $_ ([]; [.])) as $y | $x == $y) catch .
|
|
null
|
|
"Equality check too deep"
|
|
|
|
# regression tests for deep ordering comparisons
|
|
try ((reduce range(10001) as $_ ([]; [.])) as $x | [$x, $x] | sort) catch .
|
|
null
|
|
"Comparison too deep"
|
|
|
|
try ((reduce range(10001) as $_ ([]; [.])) as $x | [$x, $x] | unique) catch .
|
|
null
|
|
"Comparison too deep"
|
|
|
|
try ((reduce range(10001) as $_ ({}; {a: .})) as $x | [$x, $x] | sort) catch .
|
|
null
|
|
"Comparison too deep"
|
|
|
|
try ((reduce range(10001) as $_ ({}; {a: .})) as $x | [$x, $x] | unique) catch .
|
|
null
|
|
"Comparison too deep"
|