This commit improves the performance of repeating strings, by copying the result string instead of the string being repeated. Also it adds an error message when the result string is too long.
2316 lines
44 KiB
Plaintext
2316 lines
44 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|.,@urid),@sh,(@base64|.,@base64d)
|
|
"!()<>&'\"\t"
|
|
"!()<>&'\"\t"
|
|
"\"!()<>&'\\\"\\t\""
|
|
"1,\"!()<>&'\"\"\t\""
|
|
"1\t!()<>&'\"\\t"
|
|
"!()<>&'"\t"
|
|
"%21%28%29%3C%3E%26%27%22%09"
|
|
"!()<>&'\"\t"
|
|
"'!()<>&'\\''\"\t'"
|
|
"ISgpPD4mJyIJ"
|
|
"!()<>&'\"\t"
|
|
|
|
# regression test for #436
|
|
@base64
|
|
"foóbar\n"
|
|
"Zm/Ds2Jhcgo="
|
|
|
|
@base64d
|
|
"Zm/Ds2Jhcgo="
|
|
"foóbar\n"
|
|
|
|
@uri
|
|
"\u03bc"
|
|
"%CE%BC"
|
|
|
|
@urid
|
|
"%CE%BC"
|
|
"\u03bc"
|
|
|
|
@html "<b>\(.)</b>"
|
|
"<script>hax</script>"
|
|
"<b><script>hax</script></b>"
|
|
|
|
[.[]|tojson|fromjson]
|
|
["foo", 1, ["a", 1, "b", 2, {"foo":"bar"}]]
|
|
["foo",1,["a",1,"b",2,{"foo":"bar"}]]
|
|
|
|
#
|
|
# Dictionary construction syntax
|
|
#
|
|
|
|
{a: 1}
|
|
null
|
|
{"a":1}
|
|
|
|
{a,b,(.d):.a,e:.b}
|
|
{"a":1, "b":2, "c":3, "d":"c"}
|
|
{"a":1, "b":2, "c":1, "e":2}
|
|
|
|
{"a",b,"a$\(1+1)"}
|
|
{"a":1, "b":2, "c":3, "a$2":4}
|
|
{"a":1, "b":2, "a$2":4}
|
|
|
|
%%FAIL
|
|
{(0):1}
|
|
jq: error: Cannot use number (0) as object key at <top-level>, line 1:
|
|
|
|
%%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)"]
|
|
|
|
# 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]
|
|
|
|
#
|
|
# 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,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]
|
|
|
|
[foreach range(5) as $x (0; .+$x | select($x!=2); [$x,.])]
|
|
null
|
|
[[0,0],[1,1],[3,4],[4,8]]
|
|
|
|
[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 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]
|
|
|
|
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
|
|
|
|
[{"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
|
|
|
|
# This, while useless, should still compile.
|
|
reduce . as $n (.; .)
|
|
null
|
|
null
|
|
|
|
reduce range(5) as $x (0; .+$x | select($x!=2))
|
|
null
|
|
8
|
|
|
|
# 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])
|
|
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"
|
|
{"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}]
|
|
[]
|
|
|
|
.[] | 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"]
|
|
|
|
[(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]]
|
|
|
|
# trim
|
|
# \u000b is vertical tab (\v not supported by json)
|
|
map(trim), map(ltrim), map(rtrim)
|
|
[" \n\t\r\f\u000b", ""," ", "a", " a ", "abc", " abc ", " abc", "abc "]
|
|
["", "", "", "a", "a", "abc", "abc", "abc", "abc"]
|
|
["", "", "", "a", "a ", "abc", "abc ", "abc", "abc "]
|
|
["", "", "", "a", " a", "abc", " abc", " abc", "abc"]
|
|
|
|
trim, ltrim, rtrim
|
|
"\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000abc\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000"
|
|
"abc"
|
|
"abc\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000"
|
|
"\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000abc"
|
|
|
|
try trim catch ., try ltrim catch ., try rtrim catch .
|
|
123
|
|
"trim input must be a string"
|
|
"trim input must be a string"
|
|
"trim input must be a string"
|
|
|
|
indices(1)
|
|
[0,1,1,2,3,4,1,5]
|
|
[1,2,6]
|
|
|
|
indices([1,2])
|
|
[0,1,2,3,1,4,2,5,1,2,6,7]
|
|
[1,8]
|
|
|
|
indices([1,2])
|
|
[1]
|
|
[]
|
|
|
|
indices(", ")
|
|
"a,b, cd,e, fgh, ijkl"
|
|
[3,9,14]
|
|
|
|
index("!")
|
|
"здравствуй мир!"
|
|
14
|
|
|
|
.[:rindex("x")]
|
|
"正xyz"
|
|
"正"
|
|
|
|
indices("o")
|
|
"🇬🇧oo"
|
|
[2,3]
|
|
|
|
indices("o")
|
|
"ƒoo"
|
|
[1,2]
|
|
|
|
[.[]|split(",")]
|
|
["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"]
|
|
[["a"," bc"," def"," ghij"," jklmn"," a","b"," c","d"," e","f"],["a","b","c","d"," e","f","g","h"]]
|
|
|
|
[.[]|split(", ")]
|
|
["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"]
|
|
[["a","bc","def","ghij","jklmn","a,b","c,d","e,f"],["a,b,c,d","e,f,g,h"]]
|
|
|
|
[.[] * 3]
|
|
["a", "ab", "abc"]
|
|
["aaa", "ababab", "abcabcabc"]
|
|
|
|
[.[] * "abc"]
|
|
[-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 3.7, 10.0]
|
|
[null,null,"","","abc","abc","abcabcabc","abcabcabcabcabcabcabcabcabcabc"]
|
|
|
|
[. * (nan,-nan)]
|
|
"abc"
|
|
[null,null]
|
|
|
|
. * 100000 | [.[:10],.[-10:]]
|
|
"abc"
|
|
["abcabcabca","cabcabcabc"]
|
|
|
|
. * 1000000000
|
|
""
|
|
""
|
|
|
|
try (. * 1000000000) catch .
|
|
"abc"
|
|
"Repeat string result too long"
|
|
|
|
[.[] / ","]
|
|
["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"]
|
|
[["a"," bc"," def"," ghij"," jklmn"," a","b"," c","d"," e","f"],["a","b","c","d"," e","f","g","h"]]
|
|
|
|
[.[] / ", "]
|
|
["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"]
|
|
[["a","bc","def","ghij","jklmn","a,b","c,d","e,f"],["a,b,c,d","e,f,g,h"]]
|
|
|
|
map(.[1] as $needle | .[0] | contains($needle))
|
|
[[[],[]], [[1,2,3], [1,2]], [[1,2,3], [3,1]], [[1,2,3], [4]], [[1,2,3], [1,4]]]
|
|
[true, true, true, false, false]
|
|
|
|
map(.[1] as $needle | .[0] | contains($needle))
|
|
[[["foobar", "foobaz"], ["baz", "bar"]], [["foobar", "foobaz"], ["foo"]], [["foobar", "foobaz"], ["blap"]]]
|
|
[true, true, false]
|
|
|
|
[({foo: 12, bar:13} | contains({foo: 12})), ({foo: 12} | contains({})), ({foo: 12, bar:13} | contains({baz:14}))]
|
|
{}
|
|
[true, true, false]
|
|
|
|
{foo: {baz: 12, blap: {bar: 13}}, bar: 14} | contains({bar: 14, foo: {blap: {}}})
|
|
{}
|
|
true
|
|
|
|
{foo: {baz: 12, blap: {bar: 13}}, bar: 14} | contains({bar: 14, foo: {blap: {bar: 14}}})
|
|
{}
|
|
false
|
|
|
|
sort
|
|
[42,[2,5,3,11],10,{"a":42,"b":2},{"a":42},true,2,[2,6],"hello",null,[2,5,6],{"a":[],"b":1},"abc","ab",[3,10],{},false,"abcd",null]
|
|
[null,null,false,true,2,10,42,"ab","abc","abcd","hello",[2,5,3,11],[2,5,6],[2,6],[3,10],{},{"a":42},{"a":42,"b":2},{"a":[],"b":1}]
|
|
|
|
(sort_by(.b) | sort_by(.a)), sort_by(.a, .b), sort_by(.b, .c), group_by(.b), group_by(.a + .b - .c == 2)
|
|
[{"a": 1, "b": 4, "c": 14}, {"a": 4, "b": 1, "c": 3}, {"a": 1, "b": 4, "c": 3}, {"a": 0, "b": 2, "c": 43}]
|
|
[{"a": 0, "b": 2, "c": 43}, {"a": 1, "b": 4, "c": 14}, {"a": 1, "b": 4, "c": 3}, {"a": 4, "b": 1, "c": 3}]
|
|
[{"a": 0, "b": 2, "c": 43}, {"a": 1, "b": 4, "c": 14}, {"a": 1, "b": 4, "c": 3}, {"a": 4, "b": 1, "c": 3}]
|
|
[{"a": 4, "b": 1, "c": 3}, {"a": 0, "b": 2, "c": 43}, {"a": 1, "b": 4, "c": 3}, {"a": 1, "b": 4, "c": 14}]
|
|
[[{"a": 4, "b": 1, "c": 3}], [{"a": 0, "b": 2, "c": 43}], [{"a": 1, "b": 4, "c": 14}, {"a": 1, "b": 4, "c": 3}]]
|
|
[[{"a": 1, "b": 4, "c": 14}, {"a": 0, "b": 2, "c": 43}], [{"a": 4, "b": 1, "c": 3}, {"a": 1, "b": 4, "c": 3}]]
|
|
|
|
unique
|
|
[1,2,5,3,5,3,1,3]
|
|
[1,2,3,5]
|
|
|
|
unique
|
|
[]
|
|
[]
|
|
|
|
[min, max, min_by(.[1]), max_by(.[1]), min_by(.[2]), max_by(.[2])]
|
|
[[4,2,"a"],[3,1,"a"],[2,4,"a"],[1,3,"a"]]
|
|
[[1,3,"a"],[4,2,"a"],[3,1,"a"],[2,4,"a"],[4,2,"a"],[1,3,"a"]]
|
|
|
|
[min,max,min_by(.),max_by(.)]
|
|
[]
|
|
[null,null,null,null]
|
|
|
|
.foo[.baz]
|
|
{"foo":{"bar":4},"baz":"bar"}
|
|
4
|
|
|
|
.[] | .error = "no, it's OK"
|
|
[{"error":true}]
|
|
{"error": "no, it's OK"}
|
|
|
|
[{a:1}] | .[] | .a=999
|
|
null
|
|
{"a": 999}
|
|
|
|
to_entries
|
|
{"a": 1, "b": 2}
|
|
[{"key":"a", "value":1}, {"key":"b", "value":2}]
|
|
|
|
from_entries
|
|
[{"key":"a", "value":1}, {"Key":"b", "Value":2}, {"name":"c", "value":3}, {"Name":"d", "Value":4}]
|
|
{"a": 1, "b": 2, "c": 3, "d": 4}
|
|
|
|
with_entries(.key |= "KEY_" + .)
|
|
{"a": 1, "b": 2}
|
|
{"KEY_a": 1, "KEY_b": 2}
|
|
|
|
map(has("foo"))
|
|
[{"foo": 42}, {}]
|
|
[true, false]
|
|
|
|
map(has(2))
|
|
[[0,1], ["a","b","c"]]
|
|
[false, true]
|
|
|
|
has(nan)
|
|
[0,1,2]
|
|
false
|
|
|
|
keys
|
|
[42,3,35]
|
|
[0,1,2]
|
|
|
|
[][.]
|
|
1000000000000000000
|
|
null
|
|
|
|
map([1,2][0:.])
|
|
[-1, 1, 2, 3, 1000000000000000000]
|
|
[[1], [1], [1,2], [1,2], [1,2]]
|
|
|
|
# Test recursive object merge
|
|
|
|
{"k": {"a": 1, "b": 2}} * .
|
|
{"k": {"a": 0,"c": 3}}
|
|
{"k": {"a": 0, "b": 2, "c": 3}}
|
|
|
|
{"k": {"a": 1, "b": 2}, "hello": {"x": 1}} * .
|
|
{"k": {"a": 0,"c": 3}, "hello": 1}
|
|
{"k": {"a": 0, "b": 2, "c": 3}, "hello": 1}
|
|
|
|
{"k": {"a": 1, "b": 2}, "hello": 1} * .
|
|
{"k": {"a": 0,"c": 3}, "hello": {"x": 1}}
|
|
{"k": {"a": 0, "b": 2, "c": 3}, "hello": {"x": 1}}
|
|
|
|
{"a": {"b": 1}, "c": {"d": 2}, "e": 5} * .
|
|
{"a": {"b": 2}, "c": {"d": 3, "f": 9}}
|
|
{"a": {"b": 2}, "c": {"d": 3, "f": 9}, "e": 5}
|
|
|
|
[.[]|arrays]
|
|
[1,2,"foo",[],[3,[]],{},true,false,null]
|
|
[[],[3,[]]]
|
|
|
|
[.[]|objects]
|
|
[1,2,"foo",[],[3,[]],{},true,false,null]
|
|
[{}]
|
|
|
|
[.[]|iterables]
|
|
[1,2,"foo",[],[3,[]],{},true,false,null]
|
|
[[],[3,[]],{}]
|
|
|
|
[.[]|scalars]
|
|
[1,2,"foo",[],[3,[]],{},true,false,null]
|
|
[1,2,"foo",true,false,null]
|
|
|
|
[.[]|values]
|
|
[1,2,"foo",[],[3,[]],{},true,false,null]
|
|
[1,2,"foo",[],[3,[]],{},true,false]
|
|
|
|
[.[]|booleans]
|
|
[1,2,"foo",[],[3,[]],{},true,false,null]
|
|
[true,false]
|
|
|
|
[.[]|nulls]
|
|
[1,2,"foo",[],[3,[]],{},true,false,null]
|
|
[null]
|
|
|
|
flatten
|
|
[0, [1], [[2]], [[[3]]]]
|
|
[0, 1, 2, 3]
|
|
|
|
flatten(0)
|
|
[0, [1], [[2]], [[[3]]]]
|
|
[0, [1], [[2]], [[[3]]]]
|
|
|
|
flatten(2)
|
|
[0, [1], [[2]], [[[3]]]]
|
|
[0, 1, 2, [3]]
|
|
|
|
flatten(2)
|
|
[0, [1, [2]], [1, [[3], 2]]]
|
|
[0, 1, 2, 1, [3], 2]
|
|
|
|
try flatten(-1) catch .
|
|
[0, [1], [[2]], [[[3]]]]
|
|
"flatten depth must not be negative"
|
|
|
|
transpose
|
|
[[1], [2,3]]
|
|
[[1,2],[null,3]]
|
|
|
|
transpose
|
|
[]
|
|
[]
|
|
|
|
ascii_upcase
|
|
"useful but not for é"
|
|
"USEFUL BUT NOT FOR é"
|
|
|
|
bsearch(0,1,2,3,4)
|
|
[1,2,3]
|
|
-1
|
|
0
|
|
1
|
|
2
|
|
-4
|
|
|
|
bsearch({x:1})
|
|
[{ "x": 0 },{ "x": 1 },{ "x": 2 }]
|
|
1
|
|
|
|
try ["OK", bsearch(0)] catch ["KO",.]
|
|
"aa"
|
|
["KO","string (\"aa\") cannot be searched from"]
|
|
|
|
# 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"
|
|
|
|
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]
|
|
|
|
# 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"]
|
|
|
|
# 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"}],"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 (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"
|
|
|
|
try (.-.) catch .
|
|
"very-long-string"
|
|
"string (\"very-long-...) and string (\"very-long-...) cannot be subtracted"
|
|
|
|
"x" * range(0; 12; 2) + "☆" * 5 | 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"
|
|
|
|
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 | . == 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}
|
|
|
|
# also "nan with payload" #2985
|
|
if have_decnum then fromjson else nan end | isnan
|
|
"nan1234"
|
|
true
|
|
|
|
|
|
# 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.67", ".89", "-876", "+5.43", 21]
|
|
[1, 3, 5.67, 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"]
|
|
|
|
# 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"
|
|
|
|
|
|
# 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"]
|
|
|
|
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"]
|