#!/bin/sh
printf '1..60\n'

set -e

xe() { "${XE:-./xe}" "$@"; }

necho() { for a; do printf '%s\n' "$a"; done; }

check_output() {
	msg=$1
	expected="$(cat)"
	shift
	if output="$(eval "$@" 2>&1)"; then
		if [ "$output" = "$expected" ]; then
			printf 'ok - %s\n' "$msg"
			return
		fi
	fi
	printf 'not ok - %s\n' "$msg"
	if [ "$output" != "$expected" ]; then
		printf 'Unexpected output:\n%s\n' "$output" | sed 's/^/# /'
	fi
}

printf '# simple tests\n'

check_output 'single argument run' 'necho 1 2 3 | xe echo' <<EOF
1
2
3
EOF

check_output 'dual argument run' 'necho 1 2 3 4 5 | xe -N2 echo' <<EOF
1 2
3 4
5
EOF

check_output 'unlimited argument run' 'necho 1 2 3 4 5 | xe -N0 echo' <<EOF
1 2 3 4 5
EOF

check_output 'empty input run' 'true | xe echo a' <<EOF
EOF

check_output 'dry run' 'necho a b c | xe -n echo x' <<EOF
echo x a
echo x b
echo x c
EOF

check_output 'dry run quoting' 'necho a "b b" c | xe -n echo x' <<EOF
echo x a
echo x 'b b'
echo x c
EOF

check_output 'verbose run' 'necho a b c | xe -v echo x' <<EOF
echo x a
x a
echo x b
x b
echo x c
x c
EOF

check_output 'with no command' 'necho 1 2 3 | xe -N2' <<EOF
1
2
3
EOF

check_output 'using {}' 'necho 1 2 3 | xe echo a {} x' <<EOF
a 1 x
a 2 x
a 3 x
EOF

check_output 'using {} twice' 'necho 1 2 3 | xe echo {} x {}' <<EOF
1 x {}
2 x {}
3 x {}
EOF

check_output 'using -I%' 'necho 1 2 3 | xe -I% echo {} x %' <<EOF
{} x 1
{} x 2
{} x 3
EOF

check_output 'using -I "" to disable' 'necho 1 2 3 | xe -I "" echo {} x %' <<EOF
{} x % 1
{} x % 2
{} x % 3
EOF

check_output 'using {} with multiple arguments' 'necho 1 2 3 | xe -N2 echo a {} x {}' <<EOF
a 1 2 x {}
a 3 x {}
EOF

check_output 'using -0' 'printf "foo\0bar\0quux" | xe -0 echo' <<EOF
foo
bar
quux
EOF

check_output 'using -a' 'xe -a echo -- 1 2 3' <<EOF
1
2
3
EOF

check_output 'using -a with no arguments' 'xe -a echo' <<EOF
EOF

check_output 'using -a with no command' 'xe -N2 -a -- 1 2 3' <<EOF
1
2
3
EOF

check_output 'using -A%' 'xe -A% echo -- % 1 2 3' <<EOF
-- 1
-- 2
-- 3
EOF

check_output 'using -A% with no arguments' 'xe -A% echo || true' <<EOF
xe: '-A %' used but no separator '%' found in command line.
EOF

check_output 'using -A% with no command' 'xe -N2 -A% % 1 2 3' <<EOF
1
2
3
EOF

check_output 'using -f' 'necho notme | xe -f tests echo | grep ^notme || echo success' <<EOF
success
EOF

check_output 'using -s' 'necho 1 2 3 | xe -s "echo x\$1"' <<EOF
x1
x2
x3
EOF

check_output 'using -s with -N0' 'necho 1 2 3 | xe -N0 -s "echo x\$@"' <<EOF
x1 2 3
EOF

check_output 'using -s with -a' 'xe -s "echo x\$@" -a 1 2 3' <<EOF
x1
x2
x3
EOF

check_output 'using -s with -a' 'xe -a -s "echo x\$@" 1 2 3' <<EOF
x1
x2
x3
EOF

check_output 'using -s with -a' 'xe -a -s "echo x\$@" -- 1 2 3' <<EOF
x1
x2
x3
EOF

check_output 'with ITER' 'xe -a -s "echo \$ITER" -- a b c' <<EOF
1
2
3
EOF

check_output 'is eager' '{ echo 1; sleep 1; echo 11 >/dev/stderr; echo 2; } | xe echo' <<EOF
1
11
2
EOF

check_output 'using -L' '{ echo 1; sleep 1; echo 2; sleep 1; echo 3; } | xe -j2 -L -s "printf \$1; sleep 1; echo \$1"' <<EOF
11
22
33
EOF

check_output 'using -LL' '{ echo 1; sleep 1; echo 2; sleep 1; echo 3; } | xe -j2 -LL -s "printf \$1; sleep 1; echo \$1"' <<EOF
0001= 11
0002= 22
0003= 33
EOF

check_output 'using -vvL' '{ echo 1; sleep 1; echo 2; sleep 1; echo 3; } | xe -j2 -vvL -s "printf %s \$1; sleep 1; echo \$1" | wc -l | tr -d " "' <<EOF
9
EOF

printf '# error handling\n'

check_output 'exit code on success' 'true | xe; echo $?' <<EOF
0
EOF

check_output 'exit code on other error' 'true | xe -j NaN 2>/dev/null || echo $?' <<EOF
1
EOF

check_output 'exit code on when command fails with 1-125' 'necho a | xe -s "exit 42" || echo $?' <<EOF
123
EOF

check_output 'exit code on when command fails with 255' 'necho a | xe -s "exit 255" 2>/dev/null || echo $?' <<EOF
124
EOF

check_output 'exit code when process was killed' 'necho a | xe -s "exec /bin/kill -HUP \$\$" 2>/dev/null || echo $?' <<EOF
125
EOF

# possible false positive result when exec returns ENOENT instead of ENOTDIR here
check_output 'exit code when command cannot be run' 'necho a | xe /dev/null/calc.exe 2>/dev/null || echo $?' <<EOF
126
EOF

check_output 'exit code when command was not found' 'necho a | xe /bin/calc.exe 2>/dev/null || echo $?' <<EOF
127
EOF

check_output 'exit code on empty input when run with -R' 'true | xe -R echo a || echo $?' <<EOF
122
EOF

check_output 'doesn'\''t stop on errors by default' 'necho a b c | xe -s "if [ b = \$1 ]; then false; else echo \$1; fi" || echo $?' <<EOF
a
c
123
EOF

check_output 'stops on first error with -F' 'necho a b c | xe -F -s "if [ b = \$1 ]; then false; else echo \$1; fi" 2>/dev/null || echo $?' <<EOF
a
123
EOF

check_output 'should close stdin when arguments were read from it' 'necho a b c | xe -s "sed q"' <<EOF
EOF

check_output 'should not close stdin when arguments were read from command line' 'yes | xe -a -s "sed q" -- 1 2 3' <<EOF
y
y
y
EOF

check_output 'should not close stdin when arguments were read from file' 'yes | xe -f tests -s "sed q" 2>&1 | sed 3q' <<EOF
y
y
y
EOF

printf '# regressions\n'

check_output '0fb64a4 quoting of empty strings' 'printf "foo\n\n" | xe -N2 -v true' <<EOF
true foo ''
EOF

printf '# limit checks, expecting maximal POSIX limits available\n'

check_output 'argscap check' 'dd if=/dev/zero bs=1 count=17711 2>/dev/null | tr "\0" "\012" | xe -N0 -s "echo \$#"' <<EOF
8187
8187
1337
EOF

bloat() { perl -e 'print "x"x8000, "\n" for 1..42'; }
check_output 'argslen check' 'bloat | xe -N0 -s "echo \$#"' <<EOF
16
16
10
EOF

printf '# percent rules\n'

check_output 'literal matches' 'xe -ap bcd echo found -- abc bcd defg' <<EOF
found
EOF

check_output 'multiple patterns' 'xe -ap one echo 1 + two echo 2 + three echo 3 -- zero one two three four five' <<EOF
1
2
3
EOF

check_output '{} expansion' 'xe -ap bcd echo {} -- abc bcd defg' <<EOF
bcd
EOF

check_output '% expansion' 'xe -ap bcd echo % -- abc bcd defg' <<EOF
bcd
EOF

check_output 'dirnames' 'xe -ap bcd echo % -- abc bcd /tmp/bcd /tmp/abc' <<EOF
bcd
/tmp/bcd
EOF

check_output '? glob' 'xe -ap "b?d" echo % -- abc bcd b3d defg' <<EOF
bcd
b3d
EOF

check_output '* glob' 'xe -ap "b*d" echo % -- bd bed bad bugged bx zbd b/d' <<EOF
bd
bed
bad
bugged
EOF

check_output 'multiple * glob' 'xe -ap "b*g*d" echo % -- bd bed bugged bx zbd bagdad badger ba/gd/ad' <<EOF
bugged
bagdad
EOF

check_output 'multiple ** glob' 'xe -ap "b**g**d" echo % -- bd bed bugged bx zbd bagdad badger ba/gd/ad' <<EOF
bugged
bagdad
ba/gd/ad
EOF

check_output '/ slash' 'xe -ap a/b echo 1 + c///d echo 2 + "*" echo 3 -- a/b a//b a/ b c/d /c////d' <<EOF
1
1
3
3
2
3
EOF

check_output '[] ranges' 'xe -ap "[abc]" echo "1%" + "[d-g]" echo "2%" + "[^xyz-]" echo "3%" + "[!-vw]" echo "4%" + % echo "5%" -- a c d e g h w x -' <<EOF
1a
1c
2d
2e
2g
3h
3w
4x
5-
EOF

check_output '{} alternation' 'xe -ap "{a,bc,def*}" echo % -- x a abc bc bcd def defx xdef' <<EOF
a
bc
def
defx
EOF

check_output '% match' 'xe -ap %.c echo obj/%.o -- foo.c bar.cc meh/quux.c' <<EOF
obj/foo.o
meh/obj/quux.o
EOF
