# 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,(@base64 | @base64d) "<>&'\"\t" "<>&'\"\t" "\"<>&'\\\"\\t\"" "1,\"<>&'\"\"\t\"" "1\t<>&'\"\\t" "<>&'"\t" "%3C%3E%26'%22%09" "'<>&'\\''\"\t'" "PD4mJyIJ" "<>&'\"\t" # regression test for #436 @base64 "foóbar\n" "Zm/Ds2Jhcgo=" @base64d "Zm/Ds2Jhcgo=" "foóbar\n" @uri "\u03bc" "%CE%BC" @html "\(.)" "" "<script>hax</script>" [.[]|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 , line 1: %%FAIL {non_const:., (0):1} jq: error: Cannot use number (0) as object key at , 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 [.[]|.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]] # # 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 , 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] [first(range(.)), last(range(.)), nth(0; range(.)), nth(5; range(.)), try nth(-1; range(.)) catch .] 10 [0,9,0,5,"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 evalute 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()] is # significantly slower under valgrind than .[] = 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 , line 1: %%FAIL IGNORE MSG . as {} | null jq: error: syntax error, unexpected '}' (Unix shell quoting issues?) at , 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 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] # 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 # # 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"]] [leaf_paths] [1,[[],{"a":2}]] [[0],[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] # # 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}]} .[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] [.[] | [.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] # 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}] [] try error("\($__loc__)") catch . null "{\"file\":\"\",\"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]] 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"] [.[] / ","] ["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] 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]] ascii_upcase "useful but not for é" "USEFUL BUT NOT FOR é" bsearch(4) [1,2,3] -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] # 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"] %%FAIL module (.+1); 0 jq: error: Module metadata must be constant at , line 1: %%FAIL include "a" (.+1); 0 jq: error: Module metadata must be constant at , line 1: %%FAIL include "a" []; 0 jq: error: Module metadata must be an object at , line 1: %%FAIL include "\ "; 0 jq: error: Invalid escape at line 1, column 4 (while parsing '"\ "') at , line 1: %%FAIL include "\(a)"; 0 jq: error: Import path must be constant at , 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"}]} %%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 , 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%.) catch . 0 "number (1) and number (0) cannot be divided (remainder) because the divisor is zero" %%FAIL 1/0 jq: error: Division by zero? at , line 1: # Basic numbers tests: integers, powers of two [range(-52;52;1)] as $powers | [$powers[]|pow(2;.)|log2] == $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 , 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(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