Previously constant folding of zero division (e.x. 1/0) produces a compile error. This was incorrectly implemented by checking if the division result is infinite, so produces wrong results compared to the query where no constant folding is processed (e.x. 1e308/0.1). This patch delays the operation when the divisor is zero. This makes the results more consistent, but changes the exit code on zero division from 3 to 5. Also 0/0 now produces the zero division error, not NaN. This patch also fixes the modulo operation. Previously constant folding logic does not take care of the % operator, but now it folds if the both dividend and divisor are safe numbers to cast to the integer type, and the divisor is not zero. This patch also fixes some code that relies on undefined cast behaviors in C. The modulo operation produces NaN if either the dividend or divisor is NaN.
1978 lines
37 KiB
Plaintext
1978 lines
37 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}
|
|
null
|
|
{"x": -1}
|
|
|
|
# The input line starts with a 0xFEFF (byte order mark) codepoint
|
|
# No, there is no reason to have a byte order mark in UTF8 text.
|
|
# But apparently people do, so jq shouldn't break on it.
|
|
.
|
|
"byte order mark"
|
|
"byte order mark"
|
|
|
|
# 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"
|
|
|
|
"inter\("pol" + "ation")"
|
|
null
|
|
"interpolation"
|
|
|
|
@text,@json,([1,.]|@csv,@tsv),@html,@uri,@sh,(@base64|.,@base64d)
|
|
"!()<>&'\"\t"
|
|
"!()<>&'\"\t"
|
|
"\"!()<>&'\\\"\\t\""
|
|
"1,\"!()<>&'\"\"\t\""
|
|
"1\t!()<>&'\"\\t"
|
|
"!()<>&'"\t"
|
|
"%21%28%29%3C%3E%26%27%22%09"
|
|
"'!()<>&'\\''\"\t'"
|
|
"ISgpPD4mJyIJ"
|
|
"!()<>&'\"\t"
|
|
|
|
# regression test for #436
|
|
@base64
|
|
"foóbar\n"
|
|
"Zm/Ds2Jhcgo="
|
|
|
|
@base64d
|
|
"Zm/Ds2Jhcgo="
|
|
"foóbar\n"
|
|
|
|
@uri
|
|
"\u03bc"
|
|
"%CE%BC"
|
|
|
|
@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:
|
|
|
|
%%FAIL
|
|
{non_const:., (0):1}
|
|
jq: error: Cannot use number (0) as object key at <top-level>, line 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)"]
|
|
|
|
#
|
|
# 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]
|
|
|
|
#
|
|
# 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
|
|
|
|
.[-2]
|
|
[1,2,3]
|
|
2
|
|
|
|
[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,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]
|
|
|
|
[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:
|
|
|
|
[.[]|[.,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]
|
|
|
|
[limit(3; .[])]
|
|
[11,22,33,44,55,66,77,88,99]
|
|
[11,22,33]
|
|
|
|
[limit(0; error)]
|
|
"badness"
|
|
[]
|
|
|
|
[limit(1; 1, error)]
|
|
"badness"
|
|
[1]
|
|
|
|
[first(range(.)), last(range(.))]
|
|
10
|
|
[0,9]
|
|
|
|
[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 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 IGNORE MSG
|
|
. as [] | null
|
|
jq: error: syntax error, unexpected ']', expecting '$' or '[' or '{' (Unix shell quoting issues?) at <top-level>, line 1:
|
|
|
|
%%FAIL IGNORE MSG
|
|
. as {} | null
|
|
jq: error: syntax error, unexpected '}' (Unix shell quoting issues?) at <top-level>, line 1:
|
|
|
|
# [.,(.[] | {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]
|
|
|
|
[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]
|
|
|
|
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
|
|
|
|
[{"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]
|
|
|
|
#
|
|
# 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
|
|
|
|
# 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]
|
|
|
|
# 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])
|
|
pick(last)
|
|
[[10,20],30]
|
|
[null,30]
|
|
|
|
#
|
|
# 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"
|
|
{"a":[{"b":5}]}
|
|
"Cannot index number with string \"b\""
|
|
"Cannot index object with number"
|
|
{"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]
|
|
|
|
[.[] | [.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}]
|
|
[]
|
|
|
|
[1,error,2]
|
|
null
|
|
[1,2]
|
|
|
|
[1,error(null),2]
|
|
0
|
|
[1,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"]
|
|
|
|
[(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]]
|
|
|
|
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]
|
|
|
|
[.[]|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]
|
|
|
|
[.[] / ","]
|
|
["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,2,4)
|
|
[1,2,3]
|
|
-1
|
|
1
|
|
-4
|
|
|
|
# strptime tests are in optional.test
|
|
|
|
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"
|
|
|
|
gmtime
|
|
1425599507
|
|
[2015,2,5,23,51,47,4,63]
|
|
|
|
# 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"
|
|
|
|
# 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]
|
|
|
|
%%FAIL
|
|
module (.+1); 0
|
|
jq: error: Module metadata must be constant at <top-level>, line 1:
|
|
|
|
%%FAIL
|
|
module []; 0
|
|
jq: error: Module metadata must be an object at <top-level>, line 1:
|
|
|
|
%%FAIL
|
|
include "a" (.+1); 0
|
|
jq: error: Module metadata must be constant at <top-level>, line 1:
|
|
|
|
%%FAIL
|
|
include "a" []; 0
|
|
jq: error: Module metadata must be an object at <top-level>, line 1:
|
|
|
|
%%FAIL
|
|
include "\ "; 0
|
|
jq: error: Invalid escape at line 1, column 4 (while parsing '"\ "') at <top-level>, line 1:
|
|
|
|
%%FAIL
|
|
include "\(a)"; 0
|
|
jq: error: Import path must be constant at <top-level>, line 1:
|
|
|
|
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"}]}
|
|
|
|
modulemeta | .deps |= length
|
|
"c"
|
|
{"whatever":null,"deps":6}
|
|
|
|
%%FAIL IGNORE MSG
|
|
import "syntaxerror" as e; .
|
|
jq: error: syntax error, unexpected ';', expecting $end (Unix shell quoting issues?) at /home/nico/ws/jq/tests/modules/syntaxerror/syntaxerror.jq, line 1:
|
|
|
|
%%FAIL IGNORE MSG
|
|
%::wat
|
|
jq: error: syntax error, unexpected '%', expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
|
|
|
|
import "test_bind_order" as check; check::check
|
|
null
|
|
true
|
|
|
|
try -. catch .
|
|
"very-long-string"
|
|
"string (\"very-long-...) cannot be negated"
|
|
|
|
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\":{...) cannot be added"
|
|
|
|
try join(",") catch .
|
|
["1","2",[3,4,5]]
|
|
"string (\"1,2,\") and array ([3,4,5]) 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 IGNORE MSG
|
|
}
|
|
jq: error: syntax error, unexpected INVALID_CHARACTER, expecting $end (Unix shell quoting issues?) at <top-level>, line 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
|
|
[13911860366432393]
|
|
"13911860366432393"
|
|
|
|
.x | tojson
|
|
{"x":13911860366432393}
|
|
"13911860366432393"
|
|
|
|
13911860366432393 == 13911860366432392
|
|
null
|
|
false
|
|
|
|
|
|
# Applying arithmetic to the value will truncate the result to double
|
|
|
|
. - 10
|
|
13911860366432393
|
|
13911860366432382
|
|
|
|
.[0] - 10
|
|
[13911860366432393]
|
|
13911860366432382
|
|
|
|
.x - 10
|
|
{"x":13911860366432393}
|
|
13911860366432382
|
|
|
|
. |= try . catch .
|
|
1
|
|
1
|
|
|
|
# abs, fabs, length
|
|
abs
|
|
"abc"
|
|
"abc"
|
|
|
|
map(abs)
|
|
[-0, 0, -10, -1.1]
|
|
[0,0,10,1.1]
|
|
|
|
map(fabs == length) | unique
|
|
[-10, -1.1, -1e-1, 1000000000000000002]
|
|
[true]
|
|
|
|
# The following is NOT prescriptive:
|
|
map(abs)
|
|
[0.1,1000000000000000002]
|
|
[1e-1, 1000000000000000002]
|
|
|
|
# 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}
|
|
|
|
|
|
# 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]
|
|
[1, 3, 4]
|
|
|
|
# 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"]
|