mirror of
https://github.com/jqlang/jq.git
synced 2026-10-12 02:16:58 +00:00
Printing a string wrote each character with a separate call, one fwrite() per character, or one jv_string_append_buf() for tojson and tostring, which made output of string-heavy data slow. Scan ahead for the next byte that needs escaping and write the run of bytes before it with a single call, without changing the output. Printing strings is now significantly faster, most of all for long strings with few characters to escape, and the same applies to tojson and tostring. With --ascii-output, text that is almost all non-ASCII is about the same speed, since nearly every byte is escaped anyway.
2831 lines
57 KiB
Plaintext
2831 lines
57 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"}]]
|
|
|
|
# Put escapes on both sides of runs of bytes that need no escaping
|
|
map(tojson)
|
|
["abcdefg\"", "abcdefgh\\", "abcdefghi\u0001j", "abcdefghijklmno\u007f", "abcdefgh\té", "abcdefghijklmnop\n"]
|
|
["\"abcdefg\\\"\"","\"abcdefgh\\\\\"","\"abcdefghi\\u0001j\"","\"abcdefghijklmno\\u007f\"","\"abcdefgh\\té\"","\"abcdefghijklmnop\\n\""]
|
|
|
|
[range(18) as $i | ("\"", "\\", "\u0001", "\u007f", "é", "😀") as $c | "abcdefghijklmnopq"[:$i] + $c + "abcdefghijklmnopq"[$i:] | (tojson | fromjson) == .] | all
|
|
null
|
|
true
|
|
|
|
#
|
|
# 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
|
|
|
|
has(infinite)
|
|
[0,1,2]
|
|
false
|
|
|
|
has(-infinite)
|
|
[0,1,2]
|
|
false
|
|
|
|
del(.[infinite])
|
|
[1,2,3]
|
|
[1,2,3]
|
|
|
|
del(.[-infinite])
|
|
[1,2,3]
|
|
[1,2,3]
|
|
|
|
has(1e10)
|
|
[0,1,2]
|
|
false
|
|
|
|
has(-1e10)
|
|
[0,1,2]
|
|
false
|
|
|
|
del(.[1e10])
|
|
[1,2,3]
|
|
[1,2,3]
|
|
|
|
del(.[-1e10])
|
|
[1,2,3]
|
|
[1,2,3]
|
|
|
|
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"
|