NAME invalid_format
RUN {{BPFTRACE}} -q -f jsonx -e 'begin { @scalar = 5;  }'
EXPECT ERROR: Invalid output format "jsonx"
WILL_FAIL

NAME scalar
PROG begin { @scalar = 5;  }
EXPECT_JSON runtime/outputs/scalar.json

NAME scalar_str
PROG begin { @scalar_str = "a b \n d e";  }
EXPECT_JSON runtime/outputs/scalar_str.json

NAME complex
PROG begin { @complex[comm,2] = 5;  }
EXPECT_JSON runtime/outputs/complex.json

NAME map
PROG begin { @map["key1"] = 2; @map["key2"] = 3;  }
EXPECT_JSON runtime/outputs/map.json

NAME multiple maps
PROG begin { @map1["key1"] = 2; @map2["key2"] = 3;  }
EXPECT_JSON runtime/outputs/multiple_maps.ndjson

NAME histogram
PROG begin { @hist = hist(2); @hist = hist(1025);  }
EXPECT_JSON runtime/outputs/hist.json

NAME histogram zero
PROG begin { @hist = hist(2); zero(@hist);  }
EXPECT_JSON runtime/outputs/hist_zero.json

NAME multiple histograms
PROG begin { @["bpftrace"] = hist(2); @["curl"] = hist(-1); @["curl"] = hist(0); @["curl"] = hist(511); @["curl"] = hist(1024); @["curl"] = hist(1025);  }
EXPECT_JSON runtime/outputs/hist_multiple.json

NAME multiple histograms multiple keys
PROG begin { @["bpftrace", 2] = hist(2);@["curl", 3] = hist(511); @["curl", 3] = hist(1024);  }
EXPECT_JSON runtime/outputs/hist_multiple_multiple_keys.json

NAME histogram-finegrain
PROG begin { $i = 0; while ($i < 1024) { @ = hist($i, 3); $i++; }  }
EXPECT_JSON runtime/outputs/hist_2args.json

NAME linear histogram
PROG begin { @h = lhist(2, 0, 100, 10); @h = lhist(50, 0, 100, 10); @h = lhist(1000, 0, 100, 10);  }
EXPECT_JSON runtime/outputs/lhist.json

NAME linear histogram zero
PROG begin { @h = lhist(2, 0, 100, 10); zero(@h);  }
EXPECT_JSON runtime/outputs/lhist_zero.json

NAME multiple linear histograms
PROG begin { @stats["bpftrace"] = lhist(2, 0, 100, 10); @stats["curl"] = lhist(50, 0, 100, 10); @stats["bpftrace"] = lhist(1000, 0, 100, 10);  }
EXPECT_JSON runtime/outputs/lhist_multiple.json

NAME stats
PROG begin { @stats = stats(2); @stats = stats(10);  }
EXPECT_JSON runtime/outputs/stats.json

NAME multiple stats
PROG begin { @stats["curl"] = stats(2); @stats["zsh"] = stats(10);  }
EXPECT_JSON runtime/outputs/stats_multiple.json

NAME printf
RUN {{BPFTRACE}} -q -f json -e 'begin { printf("test %d", 5);  }'
EXPECT {"type": "printf", "data": "test 5"}

NAME printf_escaping
RUN {{BPFTRACE}} -q -f json -e 'begin { printf("test \r \n \t \\ \" bar");  }'
EXPECT {"type": "printf", "data": "test \r \n \t \\ \" bar"}

NAME time
RUN {{BPFTRACE}} -q -f json -e 'begin { time();  }'
EXPECT_REGEX ^{"type": "time", "data": "[0-9]*:[0-9]*:[0-9]*\\n"}$

NAME syscall
RUN {{BPFTRACE}} --unsafe -f json -e 'begin { system("echo a b c");  }'
EXPECT {"type": "syscall", "data": "a b c\n"}

NAME join_delim
RUN {{BPFTRACE}} --unsafe -f json -e 'tracepoint:syscalls:sys_enter_execve { join(args.argv, ","); }' -c "./testprogs/syscall execve /bin/echo 'A'"
EXPECT {"type": "join", "data": "/bin/echo,'A'"}

NAME cat
RUN {{BPFTRACE}} -f json -e 'begin { cat("/proc/uptime");  }'
EXPECT_REGEX ^{"type": "cat", "data": "[0-9]*.[0-9]* [0-9]*.[0-9]*\\n"}$

NAME strerror
RUN {{BPFTRACE}} -f json -e 'begin { print((strerror(7)));  }'
EXPECT {"type": "value", "data": "Argument list too long"}

# Careful with '[' and ']', they are read by the test engine as a regex
# character class, so make sure to escape them.
NAME tuple
RUN {{BPFTRACE}} -q -f json -e 'begin { @ = (1, 2, "string", (4, 5));  }'
EXPECT {"type": "map", "data": {"@": [1,2,"string",[4,5]]}}

NAME tuple_with_struct
RUN {{BPFTRACE}} -f json -e 'struct Foo { int m; int n; } uprobe:./testprogs/simple_struct:func { $f = *((struct Foo *) arg0); @ = (0, $f); exit(); }'
EXPECT {"type": "map", "data": {"@": [0,{"m": 2, "n": 3}]}}
AFTER ./testprogs/simple_struct

NAME tuple_with_escaped_string
RUN {{BPFTRACE}} -q -f json -e 'begin { @ = (1, 2, "string with \"quotes\"");  }'
EXPECT {"type": "map", "data": {"@": [1,2,"string with \"quotes\""]}}

NAME print_non_map
RUN {{BPFTRACE}} -q -f json -e 'begin { $x = 5; print($x); exit() }'
EXPECT {"type": "value", "data": 5}
TIMEOUT 1

NAME print_non_map_builtin
RUN {{BPFTRACE}} -q -f json -e 'begin { print(comm); exit() }'
EXPECT {"type": "value", "data": "bpftrace"}
TIMEOUT 1

NAME print_non_map_tuple
RUN {{BPFTRACE}} -q -f json -e 'begin { $t = (1, 2, "string"); print($t); exit() }'
EXPECT {"type": "value", "data": [1,2,"string"]}
TIMEOUT 1

NAME print_non_map_struct
RUN {{BPFTRACE}} -f json -e 'struct Foo { int m; int n; } uprobe:./testprogs/simple_struct:func { $f = *((struct Foo *) arg0); print($f); exit(); }'
EXPECT {"type": "value", "data": {"m": 2, "n": 3}}
AFTER ./testprogs/simple_struct

NAME print_non_map_nested_struct
RUN {{BPFTRACE}} -f json -e 'struct Foo { struct { int m[1] } y; struct { int n; } a; } uprobe:./testprogs/simple_struct:func { $f = *((struct Foo *) arg0); print($f); exit(); }'
EXPECT {"type": "value", "data": {"y": {"m": [2]}, "a": {"n": 3}}}
AFTER ./testprogs/simple_struct

NAME print_avg_map_args
RUN {{BPFTRACE}} -q -f json -e 'begin { @["a"] = avg(10); @["b"] = avg(20); @["c"] = avg(30); @["d"] = avg(40); print(@, 2, 10); clear(@);  }'
EXPECT {"type": "stats", "data": {"@": {"c": 3, "d": 4}}}
TIMEOUT 1

NAME print_avg_map_with_large_top
RUN {{BPFTRACE}} -q -f json -e 'begin { @["a"] = avg(10); @["b"] = avg(20); @["c"] = avg(30); @["d"] = avg(40); print(@, 10, 10); clear(@);  }'
EXPECT {"type": "stats", "data": {"@": {"a": 1, "b": 2, "c": 3, "d": 4}}}
TIMEOUT 1

NAME print_hist_with_top_arg
RUN {{BPFTRACE}} -q -f json -e 'begin { @[1] = hist(10); @[2] = hist(20); @[3] = hist(30); print(@, 2); clear(@);  }'
EXPECT {"type": "hist", "data": {"@": {"2": [{"min": 16, "max": 31, "count": 1}], "3": [{"min": 16, "max": 31, "count": 1}]}}}
TIMEOUT 1

NAME print_hist_with_large_top_arg
RUN {{BPFTRACE}} -q -f json -e 'begin { @[1] = hist(10); @[2] = hist(20); @[3] = hist(30); print(@, 10); clear(@);  }'
EXPECT {"type": "hist", "data": {"@": {"1": [{"min": 8, "max": 15, "count": 1}], "2": [{"min": 16, "max": 31, "count": 1}], "3": [{"min": 16, "max": 31, "count": 1}]}}}
TIMEOUT 1

NAME helper_error
RUN {{BPFTRACE}} -k -q -f json -e 'struct foo {int a;}; begin { $tmp = ((struct foo*) 0)->a;  }'
EXPECT {"type": "helper_error", "msg": "Bad address", "helper": "probe_read", "retcode": -14, "filename": "stdin", "line": 1, "col": 37}
TIMEOUT 1

NAME cgroup_path
RUN {{BPFTRACE}} -q -f json -e 'begin { print(cgroup_path(cgroup));  }' | tail -n +2 | python3 -c 'import sys,json; print(json.load(sys.stdin))'
EXPECT_REGEX ^{'type': 'value', 'data': '.*'}$

NAME strftime
RUN {{BPFTRACE}} -q -f json -e 'begin { $t = (1, strftime("%m/%d/%y", nsecs)); print($t); exit() }' | tail -n +2 | python3 -c 'import sys,json; print(json.load(sys.stdin))'
EXPECT_REGEX ^{'type': 'value', 'data': \[1, '[0-9]{2}\/[0-9]{2}\/[0-9]{2}'\]}$
TIMEOUT 1

NAME print_hex_values
RUN {{BPFTRACE}} -q -f json -e 'begin { @=(int16*) 0x32;  }'
EXPECT {"type": "map", "data": {"@": 50}}

# To preserve backwards compat for machines parsing output, we do not symbolize enums in JSON output mode
NAME enum_not_symbolized
RUN {{BPFTRACE}} -q -f json -e 'enum { FOO = 333 }; begin { $f = FOO; print($f);  }'
EXPECT {"type": "value", "data": 333}

# But if user explicitly asks for enum symbolization, we provide it in JSON output
NAME enum_symbolized_printf
RUN {{BPFTRACE}} -q -f json -e 'enum Foo { ONE = 1, TWO = 2, OTHER = 99999 }; begin { printf("%d %s %d %s %d %s\n", ONE, ONE, TWO, TWO, OTHER, OTHER); exit() }'
EXPECT {"type": "printf", "data": "1 ONE 2 TWO 99999 OTHER\n"}

# Note: if we fix the underlying issue, which is that we don't support unions
# or anon structs, then we will need to change/delete this test
NAME none type
RUN {{BPFTRACE}} -q -f json -e 'union N { int i; float f; }; struct Foo { int m; union N n; }; uprobe:./testprogs/struct_with_union:func { print(*((struct Foo *) arg0)); exit(); }'
EXPECT {"type": "value", "data": {"m": 2, "n": {"i": 5, "f": null}}}
AFTER ./testprogs/struct_with_union

NAME print bool type
RUN {{BPFTRACE}} -q -f json -e 'begin { print((true, false));  }'
EXPECT {"type": "value", "data": [true,false]}
TIMEOUT 1

NAME bench
RUN {{BPFTRACE}} -q -f json --test-mode bench -e 'bench:a { @ = count(); }'
EXPECT_REGEX {"type": "benchmark_results", "data": {"a": \d+}}
TIMEOUT 2

NAME bench multiple
RUN {{BPFTRACE}} -q -f json --test-mode bench -e 'bench:a { @a++; } bench:b { @b++; } bench:c { @c++; }'
EXPECT_REGEX {"type": "benchmark_results", "data": {"a": \d+, "b": \d+, "c": \d+}}
TIMEOUT 5

NAME attached probes
RUN {{BPFTRACE}} -f json -e 'i:s:1 { exit(); }'
EXPECT {"type": "attached_probes", "count": 1, "data": {"probes": 1}}
TIMEOUT 5
