#    rpmmacro.at: test rpm macros
#
AT_BANNER([RPM macros])

AT_SETUP([macro path])
AT_KEYWORDS([macros])
RPMDB_INIT

# .rpmmacros exists, new directory not
RPMTEST_CHECK([[
rm -f ~/.config/rpm
touch ~/.rpmmacros
runroot rpm --showrc | awk '/^Macro path/{print(a[split($0,a,":")])}'
]],
[0],
[~/.rpmmacros
],
[])

# prefer new style if it exists
RPMTEST_CHECK([[
mkdir -p ~/.config/rpm
runroot rpm --showrc | awk '/^Macro path/{print(a[split($0,a,":")])}'
]],
[0],
[~/.config/rpm/macros
],
[])

# prefer new style if no config exists
RPMTEST_CHECK([[
rm -f ~/.config/rpm/macros ~/.rpmmacros
runroot --setenv  XDG_CONFIG_HOME "~/.zzz" rpm --showrc | awk '/^Macro path/{print(a[split($0,a,":")])}'
]],
[0],
[~/.zzz/rpm/macros
],
[])
RPMTEST_CLEANUP

# ------------------------------
AT_SETUP([simple rpm --eval])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm --define "this that" --eval '%{this}' --eval '%not_defined' --eval '%{not_defined}' --eval '%{}'
],
[0],
[that
%not_defined
%{not_defined}
%{}
])

# This behavior is relied on by countless specs and various rpm internals
# too, and most likely can never be changed.
RPMTEST_CHECK([
runroot rpm --eval '%{not_defined}'
],
[0],
[%{not_defined}
],
[])
RPMTEST_CLEANUP

# ------------------------------
AT_SETUP([invalid rpm --eval])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm --eval '%define _ that'
],
[1],
[],
[error: Macro %_ has illegal name (%define)
])
RPMTEST_CLEANUP

# ------------------------------
AT_SETUP([invalid rpm --define])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm --define "_ that"
runroot rpm --define "undefine that"
],
[1],
[],
[error: Macro %_ has illegal name (%define)
error: Macro %undefine is a built-in (%define)
])
RPMTEST_CLEANUP

AT_SETUP([rpm --undefine])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm --define "this that" --eval '1. %{this}' --undefine 'this' --eval '2. %{this'}
runroot rpm --eval '1. %{this}' --define "this that" --eval '2. %{this}' --undefine 'this' --eval '3. %{this'}
],
[0],
[1. that
2. %{this}
1. %{this}
2. that
3. %{this}
])
RPMTEST_CLEANUP

AT_SETUP([simple true conditional rpm --eval])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm --define "this that" --eval '%{?this}'
],
[0],
[that
])
RPMTEST_CLEANUP

AT_SETUP([simple false conditional rpm --eval])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm --define "this that" --eval '%{?that}'
],
[0],
[
])
RPMTEST_CLEANUP

AT_SETUP([nested macro in name])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm --define "this that" --define "that_that foo" --eval '%{expand:%{%{this}_that}}'
],
[0],
[foo
])
RPMTEST_CLEANUP

AT_SETUP([recursive macro])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm --define 'aaa %aaa' --eval '%aaa'
],
[1],
[],
[error: Too many levels of recursion in macro expansion. It is likely caused by recursive macro declaration.
])
RPMTEST_CLEANUP

AT_SETUP([recursive expression])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm --define 'aaa %\\[%aaa\\]' --eval '%aaa'
],
[1],
[],
[error: Too many levels of recursion in macro expansion. It is likely caused by recursive macro declaration.
])
RPMTEST_CLEANUP

AT_SETUP([parametrized macro 1])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
RPMDB_INIT
cat << EOF > ${RPMTEST}/mtest
%bar() bar
%foo()\\
%bar\\
foo 1\\
%{bar}\\
foo 2\\
%bar x\\
foo 3\\
%{bar x}\\
foo 4\\
%bar \\
foo 5
EOF

runroot rpm --eval '%{load:/mtest}%{foo}'
],
[0],
[
bar
foo 1
bar
foo 2
bar
foo 3
bar
foo 4
bar
foo 5
],
[])
RPMTEST_CLEANUP

AT_SETUP([parametrized macro 2])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --define '%bar() "Bar %#: %{?1} %{?2}"' \
    --define '%foo() "Foo %#: %{?1} %{?2}" %bar a' \
    --eval '%foo 1 2'
],
[0],
["Foo 2: 1 2" "Bar 1: a "
])
RPMTEST_CLEANUP

AT_SETUP([parametrized macro 3])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --define '%foo() 1:%1 2:%2' \
    --eval '%foo %nil bar'
],
[0],
[1:bar 2:%2
])
RPMTEST_CLEANUP

AT_SETUP([parametrized macro 4])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --define '%bar yyy' \
    --define '%foo() %1' \
    --eval '%foo %bar' \
    --eval '%foo %%bar'
],
[0],
[yyy
%bar
])
RPMTEST_CLEANUP

AT_SETUP([parametrized macro 5])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --define '%foo() %#:%{?1:"%1"}%{?2: "%2"}' \
    --define 'bar zzz' \
    --eval '%foo 1' \
    --eval '%foo   2  ' \
    --eval '%foo 1 2' \
    --eval '%foo %{nil}' \
    --eval '%foo %{nil} xx' \
    --eval '%foo %{bar} xx' \
    --eval '%foo %{quote:   2 3  5} %{quote:%{nil}}' \
    --eval '%foo %{quote 1 2}' \
    --eval '%foo x%{quote:y}z 123' \
    --eval '%foo x%{quote:%{nil}}z' \
    --eval '%foo 1 \
bar' \
    --eval '%foo 1 \' \
],
[0],
[1:"1"
1:"2"
2:"1" "2"
0:
1:"xx"
2:"zzz" "xx"
2:"   2 3  5" ""
2:"1" "2"
2:"xyz" "123"
1:"xz"
2:"1" "\"bar
2:"1" "\"
])
RPMTEST_CLEANUP

AT_SETUP([parametrized macro 6])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --define '%foo(-) %{*}' \
    --eval '%foo 5 a -z -b2'
],
[0],
[5 a -z -b2
])
RPMTEST_CLEANUP

AT_SETUP([parametrized macro 7])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --define '%foo(zb:) %{**}' \
    --eval '%foo 5 a -z -b2'
],
[0],
[5 a -z -b2
])
RPMTEST_CLEANUP

AT_SETUP([parametrized macro 8])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --define 'foo(e:) %global bar %(/bin/echo %**)' \
    --eval '%{foo arg}' \
    --eval '%bar'
],
[0],
[
arg
])
RPMTEST_CLEANUP

AT_SETUP([uncompress macro 1])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --define "__rpmuncompress /my/bin/rpmuncompress" \
    --eval "%{uncompress:/data/SOURCES/hello-2.0.tar.gz}"
],
[0],
[/my/bin/rpmuncompress /data/SOURCES/hello-2.0.tar.gz
])
RPMTEST_CLEANUP

AT_SETUP([uncompress 1])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
RPMDB_INIT
runroot_other ${RPM_CONFIGDIR_PATH}/rpmuncompress /data/SOURCES/hello-2.0.tar.gz | tar t
],
[0],
[hello-2.0/
hello-2.0/COPYING
hello-2.0/hello.spec
hello-2.0/hello.c
hello-2.0/Makefile
hello-2.0/README
hello-2.0/FAQ
])
RPMTEST_CLEANUP

AT_SETUP([uncompress 2])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
RPMDB_INIT
echo xxxxxxxxxxxxxxxxxxxxxxxxx > ${RPMTEST}/tmp/"some%%ath"
runroot_other ${RPM_CONFIGDIR_PATH}/rpmuncompress "/tmp/some%%ath"
],
[0],
[xxxxxxxxxxxxxxxxxxxxxxxxx
])
RPMTEST_CLEANUP

AT_SETUP([uncompress 3])
AT_KEYWORDS([macros rpmuncompress])
RPMDB_INIT

RPMTEST_CHECK([
runroot_other ${RPM_CONFIGDIR_PATH}/rpmuncompress -x -C /tmp/test-1.2.3 /data/SOURCES/test-1.2.3.zip
],
[0],
[])

RPMTEST_CHECK([
runroot_other ${RPM_CONFIGDIR_PATH}/rpmuncompress -x -C /tmp/test-1.2.3-7 /data/SOURCES/test-1.2.3.7z
],
[0],
[])


RPMTEST_CHECK([
runroot_other find /tmp/test-1.2.3 | sort
],
[0],
[/tmp/test-1.2.3
/tmp/test-1.2.3/.gitignore
/tmp/test-1.2.3/README.txt
/tmp/test-1.2.3/src
/tmp/test-1.2.3/src/README.txt
])
RPMTEST_CHECK([
runroot_other find /tmp/test-1.2.3-7 | sort
],
[0],
[/tmp/test-1.2.3-7
/tmp/test-1.2.3-7/.gitignore
/tmp/test-1.2.3-7/README.txt
/tmp/test-1.2.3-7/src
/tmp/test-1.2.3-7/src/README.txt
])
RPMTEST_CLEANUP

AT_SETUP([uncompress 4])
AT_KEYWORDS([macros rpmuncompress])
RPMDB_INIT

RPMTEST_CHECK([
runroot_other mkdir -p /tmp/1
runroot_other --chdir /tmp/1 ${RPM_CONFIGDIR_PATH}/rpmuncompress -x /data/SOURCES/test-1.2.3.zip
runroot_other --chdir /tmp/1 ${RPM_CONFIGDIR_PATH}/rpmuncompress -x /data/SOURCES/test-1.2.3.zip
],
[0],
[],
[ignore])

RPMTEST_CHECK([
runroot_other --chdir /tmp/1 find . | sort
],
[0],
[.
./test-1.2.3-beta
./test-1.2.3-beta/.gitignore
./test-1.2.3-beta/README.txt
./test-1.2.3-beta/src
./test-1.2.3-beta/src/README.txt
],
[ignore])

RPMTEST_CHECK([
runroot_other mkdir -p /tmp/2
runroot_other --chdir /tmp/2 ${RPM_CONFIGDIR_PATH}/rpmuncompress -x /data/SOURCES/test-1.2.3.7z
runroot_other --chdir /tmp/2 ${RPM_CONFIGDIR_PATH}/rpmuncompress -x /data/SOURCES/test-1.2.3.7z
],
[0],
[],
[ignore])

RPMTEST_CHECK([
runroot_other --chdir /tmp/2 find . | sort
],
[0],
[.
./test-1.2.3-beta
./test-1.2.3-beta/.gitignore
./test-1.2.3-beta/README.txt
./test-1.2.3-beta/src
./test-1.2.3-beta/src/README.txt
],
[ignore])
RPMTEST_CLEANUP

AT_SETUP([getncpus macro])
AT_KEYWORDS([macros])
# skip if nproc not available
AT_SKIP_IF([test -z "$(nproc 2>/dev/null)"])
RPMTEST_CHECK([
mem=$(expr $(getconf PAGESIZE) \* $(getconf _PHYS_PAGES) / 1024 / 1024)
expr $(runroot rpm --eval "%{getncpus}") = $(nproc)
expr $(runroot rpm --define "_smp_tasksize_thread ${mem}" --eval "%{getncpus:thread}") = 1
expr $(runroot rpm --define "_smp_tasksize_proc ${mem}" --eval "%{getncpus:proc}") = 1
],
[ignore],
[1
1
1
],
[])
RPMTEST_CLEANUP

AT_SETUP([basename macro])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --eval "%{basename:/data/SOURCES/hello-2.0.tar.gz}"
],
[0],
[hello-2.0.tar.gz
])
RPMTEST_CLEANUP

AT_SETUP([shrink macro])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --eval "%{shrink:  h e  l   lo  }"
],
[0],
[h e l lo
])
RPMTEST_CLEANUP

AT_SETUP([suffix macro])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --eval "%{suffix:/data/SOURCES/hello-2.0.tar.gz}"
],
[0],
[gz
])
RPMTEST_CLEANUP

AT_SETUP([url2path macro])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --eval "%{url2path:http://hello.org/releases/hello-2.0.tar.gz}"
],
[0],
[/releases/hello-2.0.tar.gz
])
RPMTEST_CLEANUP

AT_SETUP([macrobody macro])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --define "somedir %{_exec_prefix}/%{_lib}" \
    --eval "%{macrobody:somedir}"
runroot rpm \
    --define "something somedir" \
    --define "somedir %{_exec_prefix}/%{_lib}" \
    --eval "%{macrobody:%{something}}"
],
[0],
[%{_exec_prefix}/%{_lib}
%{_exec_prefix}/%{_lib}
])
RPMTEST_CLEANUP

AT_SETUP([rpmversion macro])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm --eval "%{rpmversion}"
],
[0],
[AT_PACKAGE_VERSION
],
[])
RPMTEST_CLEANUP

AT_SETUP([builtin macro arguments])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm --eval "%{dirname}"
runroot rpm --eval "%{dirname:}"
runroot rpm --eval "%{dirname:dir}"
runroot rpm --eval "%{dirname dir}"
runroot rpm --eval "%dirname"
runroot rpm --eval "%dirname dir"
runroot rpm --eval "%dirname /"
runroot rpm --eval "%dirname ./"
runroot rpm --eval "%dirname .."
runroot rpm --eval "%dirname ../"
runroot rpm --eval "%dirname ../foo"
runroot rpm --eval "%dirname /foo"
runroot rpm --eval "%dirname /foo/"
runroot rpm --eval "%dirname /foo/foobar"
runroot rpm --eval "%dirname /foo/foobar/"
runroot rpm --eval "%basename /foo/foobar"
runroot rpm --eval "%basename /foo/foobar/"
runroot rpm --eval "%basename /"
runroot rpm --eval "%basename foobar/"
runroot rpm --eval "%basename foobar"
runroot rpm --define '%xxx /hello/%%%%/world' --eval '%{dirname:%xxx}'
runroot rpm --eval "%{uncompress}"
runroot rpm --eval "%{uncompress:}"
runroot rpm --eval "%{getconfdir:}"
runroot rpm --eval "%{getconfdir:5}"
runroot rpm --eval "%{define:}"
runroot rpm --eval "%{define:foo}"
runroot rpm --eval "%{define:foo bar}%{foo}"
runroot rpm --eval "%{define foo}"
runroot rpm --eval "%{define foo bar baz\baz}%{foo}"
runroot rpm --eval "%{dump:foo}"
runroot rpm --eval "%{shrink:%%%%}"
runroot rpm --eval "%{shrink %%%%}"
runroot rpm --eval "%shrink %%%%"
runroot rpm --eval "%verbose foo"
],
[0],
[.
.
.
.
/
.
.
.
..
/
/
/foo
/foo
foobar
foobar
/
foobar
foobar
/hello/%%

bar
bar baz\baz
%%
%%
%%
0 foo
],
[error: %dirname: argument expected
error: %dirname: argument expected
error: %uncompress: argument expected
error: %getconfdir: unexpected argument
error: %getconfdir: unexpected argument
error: Macro % has illegal name (%define)
error: Macro %foo has empty body
error: Macro %foo has empty body
error: %dump: unexpected argument
])
RPMTEST_CLEANUP

AT_SETUP([macro arguments])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --define 'zzz xxx' \
    --eval '%{defined zzz}' \
    --eval '%{defined:zzz}' \
    --eval '%defined zzz' \
    --eval '%{defined aaa}' \
    --eval '%{defined:aaa}' \
    --eval '%defined aaa'
],
[0],
[1
1
1
0
0
0
])

RPMTEST_CHECK([
runroot rpm \
    --define 'zzz xxx' \
    --eval '%zzz' \
    --eval '%{zzz}' \
    --eval '%{zzz:}' \
    --eval '%{zzz }' \
    --eval '%{zzz aa}'
],
[0],
[xxx
xxx
xxx
xxx
xxx
],
[warning: unexpected argument to non-parametric macro %zzz
warning: unexpected argument to non-parametric macro %zzz
warning: unexpected argument to non-parametric macro %zzz
])
RPMTEST_CLEANUP

AT_SETUP([string functions])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --eval "%sub cd6317ba61e6c27b92d6bbdf2702094ff3c0c732 1 7" \
    --eval "%sub cd6317ba61e6c27b92d6bbdf2702094ff3c0c732 7 -7" \
    --eval "%sub cd6317ba61e6c27b92d6bbdf2702094ff3c0c732 -7" \
    --eval "%len cd6317ba61e6c27b92d6bbdf2702094ff3c0c732" \
    --eval "%upper abba" \
    --eval "%lower Beatles" \
    --eval "%rep ai 2" \
    --eval "%reverse live" \
    --eval "%reverse a'b" \
    --eval "%reverse a\"b" \
    --eval "%gsub aaa a b 2"
],
[0],
[cd6317b
ba61e6c27b92d6bbdf2702094ff3
3c0c732
40
ABBA
beatles
aiai
evil
b'a
b"a
bba
],
[])
RPMTEST_CLEANUP


AT_SETUP([expr macro 1])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --define "aaa 5" \
    --define "bbb 0" \
    --eval '%{expr:4*1024}' \
    --eval '%{expr:5 < 1}' \
    --eval '%{expr:(4 + 5) * 2 == 18}' \
    --eval '%{expr:%{aaa} || %{bbb}}' \
    --eval '%{expr:%{aaa} && %{bbb}}' \
    --eval '%{expr:! ""}' \
    --eval '%{expr:! "foo"}' \
    --eval '%{expr: 0 || 3}' \
    --eval '%{expr: 2 || 3}' \
    --eval '%{expr: "" || "foo"}' \
    --eval '%{expr: "bar" || "foo"}' \
    --eval '%{expr: 0 && 3}' \
    --eval '%{expr: 2 && 3}' \
    --eval '%{expr: "" && "foo"}' \
    --eval '%{expr: "bar" && "foo"}'
],
[0],
[4096
0
1
5
0
1
0
3
2
foo
bar
0
3

foo
],
[])
RPMTEST_CLEANUP

AT_SETUP([expr macro 2])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm --eval '%{expr:"a"*1}'
runroot rpm --eval '%{expr:(5+1)*4)}'
runroot rpm --eval '%{expr:"a"=!"b"}'
runroot rpm --eval '%{expr:4+}'
runroot rpm --eval '%{expr:bare}'
runroot rpm --eval '%{expr:1/0}'
runroot rpm --eval '%{expr:0 < 1 ? 2 : 1*"a"}'
runroot rpm --eval '%{expr:0 < 1 ? 1*"a" : 2}'
runroot rpm --eval '%{expr:0 < 1 ? 2 : "a"}'
runroot rpm --eval '%{expr:0 < 1 ? "a" : 2}'
],
[1],
[],
[error: types must match: "a"*1
error: syntax error in expression: (5+1)*4)
error:                                    ^
error: syntax error while parsing ==: "a"=!"b"
error:                                    ^
error: unexpected end of expression: 4+
error:                                ^
error: bare words are no longer supported, please use "...": bare
error:                                                       ^
error: division by zero: 1/0
error:                    ^
error: types must match: 0 < 1 ? 2 : 1*"a"
error: types must match: 0 < 1 ? 1*"a" : 2
error: types must match: 0 < 1 ? 2 : "a"
error: types must match: 0 < 1 ? "a" : 2
])
RPMTEST_CLEANUP

AT_SETUP([ternary expressions])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --eval '%{expr: 0 ? 2 : 3}' \
    --eval '%{expr: 1 ? 2 : 3}' \
    --eval '%{expr: 0 ? 0 ? 3 : 4 : 0 ? 6 : 7}' \
    --eval '%{expr: 0 ? 0 ? 3 : 4 : 5 ? 6 : 7}' \
    --eval '%{expr: 0 ? 2 ? 3 : 4 : 0 ? 6 : 7}' \
    --eval '%{expr: 0 ? 2 ? 3 : 4 : 5 ? 6 : 7}' \
    --eval '%{expr: 1 ? 0 ? 3 : 4 : 0 ? 6 : 7}' \
    --eval '%{expr: 1 ? 0 ? 3 : 4 : 5 ? 6 : 7}' \
    --eval '%{expr: 1 ? 2 ? 3 : 4 : 0 ? 6 : 7}' \
    --eval '%{expr: 1 ? 2 ? 3 : 4 : 5 ? 6 : 7}' \
],
[0],
[3
2
7
6
7
6
4
4
3
3
],
[])
RPMTEST_CLEANUP

AT_SETUP([expression macro level])
AT_KEYWORDS([macros])
RPMTEST_CHECK([[
runroot rpm \
	--define 'expopt(r) %[%{undefined yyy} ? "aa " : "bb "]%{-r:the -r option was set}%{!-r:the -r option was not set}' \
	--eval '%expopt' \
	--eval '%expopt -r' \
	--define 'yyy 1' \
	--eval '%expopt' \
	--eval '%expopt -r'
]],
[0],
[aa the -r option was not set
aa the -r option was set
bb the -r option was not set
bb the -r option was set
],
[])

RPMTEST_CHECK([[
runroot rpm \
	--define 'expopt(r) %{expr:%{undefined yyy} ? "aa " : "bb "}%{-r:the -r option was set}%{!-r:the -r option was not set}' \
	--eval '%expopt' \
	--eval '%expopt -r' \
	--define 'yyy 1' \
	--eval '%expopt' \
	--eval '%expopt -r'
]],
[0],
[aa the -r option was not set
aa the -r option was set
bb the -r option was not set
bb the -r option was set
],
[])
RPMTEST_CLEANUP

AT_SETUP([short circuiting])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --eval '%{expr: 0 && 1 / 0}' \
    --eval '%{expr: 1 || 1 / 0}' \
    --eval '%{expr: 1 ? 2 : 1 / 0}' \
],
[0],
[0
1
2
],
[])
RPMTEST_CLEANUP

AT_SETUP([shell expansion])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --eval "%(echo foo)"
],
[0],
[foo
])
RPMTEST_CLEANUP

AT_SETUP([expression expansion 1])
AT_KEYWORDS([macros])
RPMTEST_CHECK([[
runroot rpm \
    --define "aaa 5" \
    --define "bbb 0" \
    --eval '%[4*1024]' \
    --eval '%[5 < 1]' \
    --eval '%[%aaa]' \
    --eval '%[%{aaa}]' \
    --eval '%["%{aaa}"]' \
    --eval '%[%{?ccc}]' \
    --eval '%[v"1:2.3-4"]' \
    --eval '%[v"0" && v"0"]' \
]],
[0],
[4096
0
5
5
5
0
1:2.3-4
0
],
[])
RPMTEST_CLEANUP

AT_SETUP([expression expansion 2])
AT_KEYWORDS([macros])
RPMTEST_CHECK([[
runroot rpm --define "aaa hello" --eval '%[%aaa]'
runroot rpm --eval '%[%{foo]'
runroot rpm --eval '%[v""]'
runroot rpm --eval '%[v"1" + v"2"]'
runroot rpm --eval '%[v"1" / v"2"]'
]],
[1],
[],
[error: macro expansion returned a bare word, please use "...": %aaa
error:                                                         ^
error: expanded string: hello
error: Unterminated {: {foo 
error: invalid version: v""
error:                    ^
error: + and - not supported for versions: v"1" + v"2"
error:                                          ^
error: * and / not supported for versions: v"1" / v"2"
error:                                          ^
])
RPMTEST_CLEANUP

AT_SETUP([expression version comparison])
AT_KEYWORDS([macros])
RPMTEST_CHECK([[
runroot rpm \
    --eval '%[v"1.0" == v"1.0"]' \
    --eval '%[v"1.0~rc" < v"1.0"]' \
    --eval '%[v"1.0~rc" > v"1.0"]' \
    --eval '%[v"1.0-rc" > v"1.0"]' \
]],
[0],
[1
1
0
1
],
[])
RPMTEST_CLEANUP

AT_SETUP([simple lua --eval])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([
runroot rpm --eval '%{lua:print(5*5)}'
],
[0],
[25
])
RPMTEST_CLEANUP

AT_SETUP([lua glob])
RPMTEST_CHECK([
RPMDB_INIT
runroot_other mkdir -p aaa/{123,223,323,322,321}
runroot rpm --eval "%{lua:for i,p in ipairs(rpm.glob('aaa/3*')) do print(p..'\\n') end}"
runroot rpm --eval "%{lua:for i,p in ipairs(rpm.glob('aaa/b*', 'c')) do print(p..'\\n') end}"
],
[0],
[aaa/321
aaa/322
aaa/323

aaa/b*

],
[])
RPMTEST_CLEANUP

AT_SETUP([lua macro arguments])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([[
runroot rpm \
	--define "foo(a:) %{lua:print(opt.a, arg[1])}" \
	--define "bar() %{lua:print(rpm.expand('%foo -a'..arg[2]..' '..arg[1]))}" \
	--eval '%bar 5 3'
]],
[0],
[3	5
])
RPMTEST_CLEANUP

AT_SETUP([lua macros table])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([[
runroot rpm \
	--define "qtst() %{lua:for i=1, #arg do print(' '..i..':'..arg[i]) end}"\
	--eval "%{lua:print(macros.with('zap'), macros.without('zap'))}" \
	--eval "%{lua:print(macros.aaa)}" \
	--eval "%{lua:macros.aaa='bbb'; macros['yyy']='zzz'}" \
	--eval "%{lua:print(macros['aaa'], macros.yyy)}" \
	--eval "%{lua:macros.aaa=nil"} \
	--eval "%{lua:print(macros.aaa)}" \
	--eval "%{lua:print(macros.qtst('a c'))}" \
	--eval "%{lua:print(macros.qtst({'a', '', 'c'}))}" \
	--eval "%{lua:print(macros.qtst('%{?aaa} %{yyy}'))}" \
	--eval "%{lua:print(macros.qtst({'%{?aaa}', '%{yyy}'}))}" \
	--eval "%{lua:macros.define({'this', 'that'}); print(macros.this)}"
]],
[0],
[0	1
nil

bbb	zzz

nil
 1:a 2:c
 1:a 2: 3:c
 1:zzz
 1:%{?aaa} 2:%{yyy}
that
])

RPMTEST_CHECK([[
runroot rpm \
	--eval "%{lua:macros.defined({1,2,{}})}"
]],
[1],
[],
[[error: lua script failed: [string "<lua>"]:1: bad argument #3 to 'defined' (cannot convert to string)
]])
RPMTEST_CLEANUP

AT_SETUP([lua macros recursion])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([[
runroot rpm \
	--define "%recurse() %{lua:io.write(' '..#arg); if #arg < 16 then table.insert(arg, #arg); macros.recurse(arg) end;}" \
	--eval "%recurse"
]],
[0],
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
])
RPMTEST_CLEANUP

AT_SETUP([lua rpm extensions 1])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([
runroot rpm --eval '%{lua: rpm.define("foo bar") print(rpm.expand("%{foo}"))}'
],
[0],
[bar
])
RPMTEST_CLEANUP

AT_SETUP([lua rpm extensions 2])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([
runroot rpm --eval '%{lua: print(rpm.vercmp("1.0", "2.0"))}'
],
[0],
[-1
])
RPMTEST_CLEANUP

AT_SETUP([lua rpm isdefined])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([
runroot rpm \
	--eval '%{lua: print(rpm.isdefined("with"))}' \
	--eval '%{lua: print(rpm.isdefined("nil"))}' \
	--eval '%{lua: print(rpm.isdefined("ponies"))}'
],
[0],
[true	true
true	false
false	false
])
RPMTEST_CLEANUP

AT_SETUP([lua rpm split/unsplitargs])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([[
runroot rpm \
	--eval '%{lua: local a=rpm.splitargs("1 2 3");a[2]=" " .. a[2] .. " ";print(rpm.unsplitargs(a))}' \
| tr '\037' :
]],
[0],
[:1: : 2 : :3:
])
RPMTEST_CLEANUP

AT_SETUP([lua posix extensions])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([
runroot rpm \
  --eval '%{lua: posix.putenv("LUATEST=ok") print(posix.getenv("LUATEST"))}'
],
[0],
[ok
])
RPMTEST_CLEANUP

AT_SETUP([lua script exit behavior])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([
runroot rpm \
  --eval '%{lua: os.exit()}))}'
],
[1],
[],
[error: lua script failed: [[string "<lua>"]]:1: exit not permitted in this context]
)
RPMTEST_CLEANUP

AT_SETUP([lua script redirect2null])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([
runroot rpm \
  --eval '%{lua: posix.redirect2null()}))}'
],
[1],
[],
[warning: rpm.redirect2null(): .fork(), .exec(), .wait() and .redirect2null() are deprecated, use rpm.spawn() or rpm.execute() instead
error: lua script failed: [[string "<lua>"]]:1: redirect2null not permitted in this context]
)
RPMTEST_CLEANUP

AT_SETUP([lua library path])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([
RPMDB_INIT
f=$(run rpm --eval "%{_rpmconfigdir}/lua/foo.lua")
echo "bar = 'graak'" > ${RPMTEST}/${f}
runroot rpm \
  --eval '%{lua:require "foo"; print(bar)}'
rm -f ${RPMTEST}/${f}
],
[0],
[graak
])
RPMTEST_CLEANUP

AT_SETUP([lua auto-print])
AT_KEYWORDS([macros lua])
RPMDB_INIT
RPMTEST_CHECK([[
runroot rpm \
    --define 'foo() %{lua:return string.reverse(arg[1])}' \
    --eval '%foo hello' \
    --eval '%{lua:return 1, 2, 3}'
]],
[0],
[olleh
1	2	3
])
RPMTEST_CLEANUP

AT_SETUP([lua rpm version objects])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([
runroot rpm \
  --eval '%{lua: v1 = rpm.ver("1:4.16-5"); print(v1, v1.e, v1.v, v1.r)}' \
  --eval '%{lua: v1 = rpm.ver("4.16-1"); print(v1, v1.e, v1.v, v1.r)}' \
  --eval '%{lua: v1 = rpm.ver("4.16"); print(v1, v1.e, v1.v, v1.r)}' \
  --eval '%{lua: v1 = rpm.ver("1:4.16-5"); v2 = rpm.ver("4.4-1"); print(v1 < v2, v1 == v2, v1 > v2, v1 == v1)}'
],
[0],
[1:4.16-5	1	4.16	5
4.16-1	nil	4.16	1
4.16	nil	4.16	nil
false	false	true	true
])
RPMTEST_CLEANUP

AT_SETUP([lua rpm io stream])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([
RPMDB_INIT
runroot rpm \
  --eval '%{lua: local f = rpm.open("zzz", "w+"); f:write("gggg"); print(f:seek("cur")); f:close()}' \
  --eval '%{lua: local f = rpm.open("zzz"); print(f:read()); f:close()}' \
  --eval '%{lua: local f = rpm.open("/data/SOURCES/hello-2.0.tar.gz"); f:reopen("r.gzip"); f:seek("cur", 6); print(f:read(3)); f:close()}'
],
[0],
[4
gggg
2.0
])
RPMTEST_CLEANUP

AT_SETUP([lua functions in expressions])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([[
runroot rpm \
  --eval '%[lua:string.reverse("hello")]'
]],
[0],
[olleh
])
RPMTEST_CLEANUP

AT_SETUP([lua hooks])
AT_KEYWORDS([macros lua])
RPMTEST_CHECK([[
runroot rpm \
  --eval '%{lua:
function regtest(n) for _,v in ipairs(n) do print(" "..type(v)..":"..v);end;end
local h = rpm.register("test", regtest)
rpm.call("test", "foo", 6, 29 / 4)
rpm.unregister("test", h)
rpm.call("test", "foo", 6, 29 / 4)
}'
]],
[0],
[ string:foo number:6 number:7.25
])
RPMTEST_CLEANUP

AT_SETUP([%define + %undefine in nested levels 1])
AT_KEYWORDS([macros define undefine])
RPMTEST_CHECK([
# basic %define in nested scoping level
runroot rpm \
    --define '%foo() %{expand:%define xxx 1} %{echo:%xxx} %{expand:%undefine xxx} %{echo:%xxx}' \
    --eval .'%foo'.
],
[0],
[1
%xxx
.   .
])
RPMTEST_CLEANUP

AT_SETUP([%define + %undefine in nested levels 2])
AT_KEYWORDS([macros define])
RPMTEST_CHECK([
# %define macro once in a nested scope
runroot rpm \
    --define '%foo() %{expand:%define xxx 1} %{echo:%xxx}' \
    --eval .'%foo'. \
    --eval '%xxx'
],
[0],
[1
. .
%xxx
])
RPMTEST_CLEANUP

AT_SETUP([%define + %undefine in nested levels 3])
AT_KEYWORDS([macros define])
RPMTEST_CHECK([
# %define macro twice in a nested scope
runroot rpm \
    --define '%foo() %{expand:%define xxx 1} %{echo:%xxx} %{expand: %define xxx 2} %{echo:%xxx}' \
    --eval .'%foo'. \
    --eval '%xxx'
],
[0],
[1
2
.    .
%xxx
])

RPMTEST_CHECK([
runroot rpm --define "aa 0" --define "my() %{define:aa 1}%{define:aa 2}" --eval "%my" --eval "%aa"
],
[0],
[
0
],
[ignore])
RPMTEST_CLEANUP

AT_SETUP([%define + %undefine in nested levels 4])
AT_KEYWORDS([macros define global])
RPMTEST_CHECK([
AT_XFAIL_IF([test $RPM_XFAIL -ne 0])
# %define in a nested level covered by %global
runroot rpm \
    --define '%foo() %{expand:%define xxx 1} %{echo:%xxx} %{expand: %global xxx 2} %{echo:%xxx}' \
    --eval .'%foo'. \
    --eval '%xxx' \
    --eval '%undefine xxx' \
    --eval '%xxx'
],
[0],
[1
2
.    .
2

%xxx
])
RPMTEST_CLEANUP

AT_SETUP([%define in conditional macro])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
    --define 'dofoo() true'\
    --eval '.%{!?foo: %define foo bar}.'\
    --eval '%foo' \
    --eval '%dofoo'\
    --eval '%foo'
],
[0],
[. .
bar
true
bar
])
RPMTEST_CLEANUP

AT_SETUP([%verbose macro])
AT_KEYWORDS([macros verbose])
RPMTEST_CHECK([
runroot rpm --eval '%{verbose}'
runroot rpm -v --eval '%{verbose}'
runroot rpm --eval '%{verbose:zzz}'
runroot rpm -v --eval '%{verbose:zzz}'
],
[0],
[0
1

zzz
])
RPMTEST_CLEANUP

AT_SETUP([%exists macro])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
	--eval "%{exists:/data}" \
	--eval "%{exists:/zzz}" \
	--eval "%{exists}"
],
[1],
[1
0
],
[error: %exists: argument expected
])
RPMTEST_CLEANUP

AT_SETUP([%shescape macro])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
	--eval "%{shescape:foo's}"
],
[0],
['foo'\''s'
],
[])
RPMTEST_CLEANUP

AT_SETUP([%shescape macro with multiple arguments])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
	--eval "%{shescape foo bar's}"
],
[0],
['foo' 'bar'\''s'
],
[])

RPMTEST_CLEANUP
AT_SETUP([macro with a line starting by "{"])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm --macros "/data/macros.testfile" \
	--eval "%first" --eval "%second"],
[0],
[macro_1

macro_2
])
RPMTEST_CLEANUP

AT_SETUP([macro with %if-%endif])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpmspec -q --qf "%{summary}\n%{description}\n" /data/SPECS/iftest.spec
],
[0],
[macro 1
ccc0
ccc1
])
RPMTEST_CLEANUP

AT_SETUP([macro file errors])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
cat << EOF > macros.bad
%1 foo

%multi \\
line\\
thing

%foo bar
%bad-name 123
EOF

run rpm --macros "macros.bad" --eval "%foo"
],
[0],
[bar
],
[error: macros.bad: line 1: Macro %1 has illegal name (%define)
warning: macros.bad: line 8: Macro %bad needs whitespace before body
])
RPMTEST_CLEANUP

AT_SETUP([macro comments])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
	--macros /data/macros.testfile \
	--eval "%{comment1}" \
	--eval "%{comment2}"
],
[0],
[
read
me

see
this
],
[])
RPMTEST_CLEANUP

AT_SETUP([macro comments 2])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
	--macros /data/macros.testfile \
	--eval "%{comment3}"
],
[0],
[
read
' change this meaning
],
[])
RPMTEST_CLEANUP

AT_SETUP([macro file empty lines])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm \
	--macros /data/macros.testfile \
	--eval "%{empty0}"
],
[0],
[
some

thing

],
[])
RPMTEST_CLEANUP

AT_SETUP([macro traceback])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
for o in "-v" ""; do
    runroot rpm $o \
	--define "err %{error:bad}" \
	--define "bar %err" \
	--define "foo %bar zz" \
	--eval "xxx%{foo}yyy"
done
],
[1],
[],
[error: bad
  3<        (%error)
  2<      (%err)
  1<    (%bar)
  0<  (%foo)
xxx
error: bad
])
RPMTEST_CLEANUP

AT_SETUP([error macro return])
AT_KEYWORDS([macros lua])

RPMTEST_CHECK([
runroot rpm --eval '%{error:fail}'
],
[1],
[],
[error: fail
])

RPMTEST_CHECK([
runroot rpm --eval '%{lua:rpm.expand("%{error:fail}")}'
],
[1],
[],
[[error: fail
error: lua script failed: [string "<lua>"]:1: error expanding macro
]])

RPMTEST_CHECK([
runroot rpm --eval '%{lua:macros.error({"fail"})}'
],
[1],
[],
[[error: fail
error: lua script failed: [string "<lua>"]:1: error expanding macro
]])
RPMTEST_CLEANUP

AT_SETUP([no space left on stdout])
AT_KEYWORDS([macros])
RPMTEST_CHECK([
runroot rpm --eval 1 >/dev/full
],
[1],
[],
[Error writing to stdout: No space left on device
])
RPMTEST_CLEANUP

AT_SETUP([rpmlua])
AT_KEYWORDS([lua])
RPMTEST_SETUP
RPMTEST_CHECK([
runroot_other rpmlua /data/t1.lua a b
],
[0],
[hello world
opts:
args:
/data/t1.lua
a
b
],
[])

RPMTEST_CHECK([
runroot_other rpmlua --opts=ot: /data/t1.lua -- -t1 a
],
[0],
[hello world
opts:
t	1
args:
a
],
[])

RPMTEST_CHECK([
runroot_other rpmlua -e "print(macros.basename('/some/thing'))"
],
[0],
[thing
],
[])

RPMTEST_CHECK([
runroot_other rpmlua -e "for i, v in ipairs({'true', 'false', 'grue'}) do print(rpm.execute('/bin/'..v)) end"
],
[0],
[0.0
nil	exit code	1.0
nil	No such file or directory	2.0
],
[])

RPMTEST_CHECK([
runroot_other rpmlua -e 'pid = posix.fork(); if pid == 0 then a,b,c=rpm.redirect2null(-1); print(string.format("%s\t%s\t%s", a,b,c)); io.flush() else posix.wait(pid) end'
],
[0],
[nil	Bad file descriptor	9.0
],
[stderr])

# stderr output from the above is flaky due to the fork, post-processing
# ought to be more reliable
RPMTEST_CHECK([
cat stderr | sort
],
[0],
[warning: posix.fork(): .fork(), .exec(), .wait() and .redirect2null() are deprecated, use rpm.spawn() or rpm.execute() instead
warning: posix.wait(): .fork(), .exec(), .wait() and .redirect2null() are deprecated, use rpm.spawn() or rpm.execute() instead
warning: rpm.redirect2null(): .fork(), .exec(), .wait() and .redirect2null() are deprecated, use rpm.spawn() or rpm.execute() instead
warning: runaway fork() in Lua script
],
[])
RPMTEST_CLEANUP

AT_SETUP([lua rpm spawn])
AT_KEYWORDS([macros lua])
RPMDB_INIT
RPMTEST_CHECK([
runroot_other rpmlua -e "rpm.spawn({'echo', '1', '2', '3'})"
],
[0],
[1 2 3
],
[])

RPMTEST_CHECK([
runroot_other rpmlua \
	-e "rpm.spawn({'echo', '1', '2', '3'}, {stdout='/dev/null'})"
],
[0],
[],
[])

RPMTEST_CHECK([
runroot_other rpmlua \
	-e "rpm.spawn({'ls', '/notthere'})"
],
[0],
[],
[ls: cannot access '/notthere': No such file or directory
])

RPMTEST_CHECK([
runroot_other rpmlua \
	-e "rpm.spawn({'ls', '/notthere'}, {stderr='/dev/null'})"
],
[0],
[],
[])

RPMTEST_CHECK([
runroot_other rpmlua \
	-e "rpm.spawn({'ls', '/notthere'}, {garbage='bbb'})"
],
[255],
[],
[[error: lua script failed: [string "<execute>"]:1: invalid spawn directive: garbage
]])

RPMTEST_CHECK([
runroot_other rpmlua -e "rpm.spawn('echo', '1', '2', '3')"
],
[255],
[],
[[error: lua script failed: [string "<execute>"]:1: bad argument #1 to 'spawn' (table expected, got string)
]])

RPMTEST_CHECK([
runroot_other rpmlua -e "print(rpm.spawn({'cat'}, {stdin='aaa'}))"
],
[0],
[nil	No such file or directory	2.0
],
[])

RPMTEST_CHECK([
echo 1 2 3 > ${RPMTEST}/aaa
runroot_other rpmlua -e "rpm.spawn({'cat'}, {stdin='aaa'})"
],
[0],
[1 2 3
],
[])
RPMTEST_CLEANUP

AT_SETUP([rpmlua hooks])
AT_KEYWORDS([lua])

RPMTEST_CHECK([
run rpm --load /data/macros.hooks \
	--eval "%hook_this"
],
[0],
[1: string(whee)
2: number(3)
3: userdata(userdata: (nil))
4: number(1.2)

],
[])
RPMTEST_CLEANUP
