busybox/testsuite/awk.tests
Daniel Thau 7d06d6e186 awk: fix printf %%
A refactor of the awk printf code in
e2e3802987
appears to have broken the printf interpretation of two percent signs,
which normally outputs only one percent sign.

The patch below brings busybox awk printf behavior back into alignment
with the pre-e2e380 behavior, the busybox printf util, and other common
(awk and non-awk) printf implementations.

function                                             old     new   delta
awk_printf                                           626     672     +46

Signed-off-by: Daniel Thau <danthau at bedrocklinux.org>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-09-05 03:42:51 +02:00

473 lines
10 KiB
Bash
Executable File

#!/bin/sh
# Copyright 2007 by Denys Vlasenko <vda.linux@googlemail.com>
# Licensed under GPLv2, see file LICENSE in this source tree.
. ./testing.sh
# testing "description" "command" "result" "infile" "stdin"
testing "awk -F case 0" "awk -F '[#]' '{ print NF }'" "" "" ""
testing "awk -F case 1" "awk -F '[#]' '{ print NF }'" "0\n" "" "\n"
testing "awk -F case 2" "awk -F '[#]' '{ print NF }'" "2\n" "" "#\n"
testing "awk -F case 3" "awk -F '[#]' '{ print NF }'" "3\n" "" "#abc#\n"
testing "awk -F case 4" "awk -F '[#]' '{ print NF }'" "3\n" "" "#abc#zz\n"
testing "awk -F case 5" "awk -F '[#]' '{ print NF }'" "4\n" "" "#abc##zz\n"
testing "awk -F case 6" "awk -F '[#]' '{ print NF }'" "4\n" "" "z#abc##zz\n"
testing "awk -F case 7" "awk -F '[#]' '{ print NF }'" "5\n" "" "z##abc##zz\n"
# conditions and operators
testing "awk if operator == " "awk 'BEGIN{if(23==23) print \"foo\"}'" "foo\n" "" ""
testing "awk if operator != " "awk 'BEGIN{if(23!=23) print \"bar\"}'" "" "" ""
testing "awk if operator >= " "awk 'BEGIN{if(23>=23) print \"foo\"}'" "foo\n" "" ""
testing "awk if operator < " "awk 'BEGIN{if(2 < 13) print \"foo\"}'" "foo\n" "" ""
testing "awk if string == " "awk 'BEGIN{if(\"a\"==\"ab\") print \"bar\"}'" "" "" ""
# 4294967295 = 0xffffffff
testing "awk bitwise op" "awk '{ print or(4294967295,1) }'" "4294967295\n" "" "\n"
# we were testing for a non-empty body when deciding if a function was
# defined or not. The testcase below caused:
# awk: cmd. line:8: Call to undefined function
prg='
function empty_fun(count) {
# empty
}
END {
i=1
print "L" i "\n"
empty_fun(i + i + ++i)
print "L" i "\n"
}'
testing "awk handles empty function f(arg){}" \
"awk '$prg'" \
"L1\n\nL2\n\n" \
"" ""
prg='
function empty_fun(){}
END {empty_fun()
print "Ok"
}'
testing "awk handles empty function f(){}" \
"awk '$prg'" \
"Ok\n" \
"" ""
prg='
function outer_fun() {
return 1
}
END {
i=1
print "L" i "\n"
i += outer_fun()
print "L" i "\n"
}'
testing "awk properly handles function from other scope" \
"awk '$prg'" \
"L1\n\nL2\n\n" \
"" ""
prg='
END {
i=1
print "L" i "\n"
i + trigger_error_fun()
print "L" i "\n"
}'
testing "awk properly handles undefined function" \
"awk '$prg' 2>&1" \
"L1\n\nawk: cmd. line:5: Call to undefined function\n" \
"" ""
prg='
BEGIN {
v=1
a=2
print v (a)
}'
testing "awk 'v (a)' is not a function call, it is a concatenation" \
"awk '$prg' 2>&1" \
"12\n" \
"" ""
prg='func f(){print"F"};func g(){print"G"};BEGIN{f(g(),g())}'
testing "awk unused function args are evaluated" \
"awk '$prg' 2>&1" \
"G\nG\nF\n" \
"" ""
optional DESKTOP
testing "awk hex const 1" "awk '{ print or(0xffffffff,1) }'" "4294967295\n" "" "\n"
testing "awk hex const 2" "awk '{ print or(0x80000000,1) }'" "2147483649\n" "" "\n"
testing "awk oct const" "awk '{ print or(01234,1) }'" "669\n" "" "\n"
SKIP=
# check that "hex/oct integer" heuristic doesn't kick in on 00NN.NNN
testing "awk floating const with leading zeroes" \
"awk '{ printf \"%f %f\n\", \"000.123\", \"009.123\" }'" \
"0.123000 9.123000\n" \
"" "\n"
# long field seps requiring regex
testing "awk long field sep" \
"awk -F-- '{ print NF, length(\$NF), \$NF }'" \
"2 0 \n3 0 \n4 0 \n5 0 \n" \
"" \
"a--\na--b--\na--b--c--\na--b--c--d--"
testing "awk -F handles escapes" "awk -F'\\x21' '{print \$1}'" \
"a\n" \
"" \
"a!b\n"
# '@(samp|code|file)\{' is an invalid extended regex (unmatched '{'),
# but gawk 3.1.5 does not bail out on it.
testing "awk gsub falls back to non-extended-regex" \
"awk 'gsub(\"@(samp|code|file)\{\",\"\");'; echo \$?" "0\n" "" "Hi\n"
optional TAR BUNZIP2 FEATURE_SEAMLESS_BZ2
test x"$SKIP" != x"1" && tar xjf awk_t1.tar.bz2
testing "awk 'gcc build bug'" \
"awk -f awk_t1_opt-functions.awk -f awk_t1_opth-gen.awk <awk_t1_input | md5sum" \
"f842e256461a5ab1ec60b58d16f1114f -\n" \
"" ""
rm -rf awk_t1_* 2>/dev/null
SKIP=
Q='":"'
testing "awk NF in BEGIN" \
"awk 'BEGIN { print ${Q} NF ${Q} \$0 ${Q} \$1 ${Q} \$2 ${Q} }'" \
":0::::\n" \
"" ""
prg='
function b(tmp) {
tmp = 0;
print "" tmp; #this line causes the bug
return tmp;
}
function c(tmpc) {
tmpc = b(); return tmpc;
}
BEGIN {
print (c() ? "string" : "number");
}'
testing "awk string cast (bug 725)" \
"awk '$prg'" \
"0\nnumber\n" \
"" ""
testing "awk handles whitespace before array subscript" \
"awk 'BEGIN { arr [3] = 1; print arr [3] }'" "1\n" "" ""
# GNU awk 3.1.5's "print ERRNO" prints "No such file or directory" instead of "2",
# do we need to emulate that as well?
testing "awk handles non-existing file correctly" \
"awk 'BEGIN { getline line <\"doesnt_exist\"; print ERRNO; ERRNO=0; close(\"doesnt_exist\"); print ERRNO; print \"Ok\" }'" \
"2\n0\nOk\n" "" ""
prg='
BEGIN {
u["a"]=1
u["b"]=1
u["c"]=1
v["d"]=1
v["e"]=1
v["f"]=1
for (l in u) {
print "outer1", l;
for (l in v) {
print " inner", l;
}
print "outer2", l;
}
print "end", l;
l="a"
exit;
}'
testing "awk nested loops with the same variable" \
"awk '$prg'" \
"\
outer1 a
inner d
inner e
inner f
outer2 f
outer1 b
inner d
inner e
inner f
outer2 f
outer1 c
inner d
inner e
inner f
outer2 f
end f
" \
"" ""
prg='
BEGIN {
u["a"]=1
u["b"]=1
u["c"]=1
v["d"]=1
v["e"]=1
v["f"]=1
for (l in u) {
print "outer1", l;
for (l in v) {
print " inner", l;
break;
}
print "outer2", l;
}
print "end", l;
l="a"
exit;
}'
# It's not just buggy, it enters infinite loop. Thus disabled
false && test x"$SKIP_KNOWN_BUGS" = x"" && testing "awk nested loops with the same variable and break" \
"awk '$prg'" \
"\
outer1 a
inner d
outer2 d
outer1 b
inner d
outer2 d
outer1 c
inner d
outer2 d
end d
" \
"" ""
prg='
function f() {
for (l in v) {
print " inner", l;
return;
}
}
BEGIN {
u["a"]=1
u["b"]=1
u["c"]=1
v["d"]=1
v["e"]=1
v["f"]=1
for (l in u) {
print "outer1", l;
f();
print "outer2", l;
}
print "end", l;
l="a"
exit;
}'
# It's not just buggy, it enters infinite loop. Thus disabled
false && test x"$SKIP_KNOWN_BUGS" = x"" && testing "awk nested loops with the same variable and return" \
"awk '$prg'" \
"\
outer1 a
inner d
outer2 d
outer1 b
inner d
outer2 d
outer1 c
inner d
outer2 d
end d
" \
"" ""
prg='
BEGIN{
cnt = 0
a[cnt] = "zeroth"
a[++cnt] = "first"
delete a[cnt--]
print cnt
print "[0]:" a[0]
print "[1]:" a[1]
}'
testing "awk 'delete a[v--]' evaluates v-- once" \
"awk '$prg'" \
"\
0
[0]:zeroth
[1]:
" \
"" ""
testing "awk func arg parsing 1" \
"awk 'func f(,) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
testing "awk func arg parsing 2" \
"awk 'func f(a,,b) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
testing "awk func arg parsing 3" \
"awk 'func f(a,) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
testing "awk func arg parsing 4" \
"awk 'func f(a b) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
testing "awk handles empty ()" \
"awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" ""
testing "awk FS assignment" "awk '{FS=\":\"; print \$1}'" \
"a:b\ne\n" \
"" \
"a:b c:d\ne:f g:h"
optional FEATURE_AWK_LIBM
testing "awk large integer" \
"awk 'BEGIN{n=(2^31)-1; print n, int(n), n%1, ++n, int(n), n%1}'" \
"2147483647 2147483647 0 2147483648 2147483648 0\n" \
"" ""
SKIP=
testing "awk length(array)" \
"awk 'BEGIN{ A[1]=2; A[\"qwe\"]=\"asd\"; print length(A)}'" \
"2\n" \
"" ""
testing "awk length()" \
"awk '{print length; print length(); print length(\"qwe\"); print length(99+9)}'" \
"3\n3\n3\n3\n" \
"" "qwe"
testing "awk print length, 1" \
"awk '{ print length, 1 }'" \
"0 1\n" \
"" "\n"
testing "awk print length 1" \
"awk '{ print length 1 }'" \
"01\n" \
"" "\n"
testing "awk length == 0" \
"awk 'length == 0 { print \"foo\" }'" \
"foo\n" \
"" "\n"
testing "awk if (length == 0)" \
"awk '{ if (length == 0) { print \"bar\" } }'" \
"bar\n" \
"" "\n"
testing "awk -f and ARGC" \
"awk -f - input" \
"re\n2\n" \
"do re mi\n" \
'{print $2; print ARGC;}' \
optional FEATURE_AWK_GNU_EXTENSIONS
testing "awk -e and ARGC" \
"awk -e '{print \$2; print ARGC;}' input" \
"re\n2\n" \
"do re mi\n" \
""
SKIP=
testing "awk break" \
"awk -f - 2>&1; echo \$?" \
"awk: -:1: 'break' not in a loop\n1\n" \
"" \
'BEGIN { if (1) break; else a = 1 }'
testing "awk continue" \
"awk -f - 2>&1; echo \$?" \
"awk: -:1: 'continue' not in a loop\n1\n" \
"" \
'BEGIN { if (1) continue; else a = 1 }'
optional FEATURE_AWK_GNU_EXTENSIONS
testing "awk handles invalid for loop" \
"awk -e '{ for() }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
SKIP=
optional FEATURE_AWK_GNU_EXTENSIONS
testing "awk handles colon not preceded by ternary" \
"awk -e foo:bar: 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
SKIP=
optional FEATURE_AWK_GNU_EXTENSIONS
testing "awk errors on missing delete arg" \
"awk -e '{delete}' 2>&1" "awk: cmd. line:1: Too few arguments\n" "" ""
SKIP=
optional FEATURE_AWK_GNU_EXTENSIONS
testing "awk printf('%c') can output NUL" \
"awk '{printf(\"hello%c null\n\", 0)}'" "hello\0 null\n" "" "\n"
SKIP=
optional FEATURE_AWK_GNU_EXTENSIONS DESKTOP
testing "awk printf('%-10c') can output NUL" \
"awk 'BEGIN { printf \"[%-10c]\n\", 0 }' | od -tx1" "\
0000000 5b 00 20 20 20 20 20 20 20 20 20 5d 0a
0000015
" "" ""
SKIP=
# testing "description" "command" "result" "infile" "stdin"
testing 'awk negative field access' \
'awk 2>&1 -- '\''{ $(-1) }'\' \
"awk: cmd. line:1: Access to negative field\n" \
'' \
'anything'
# was misinterpreted as (("str"++) i) instead of ("str" (++i))
# (and was executed: "str"++ is "0", thus concatenating "0" and "1"):
testing 'awk do not allow "str"++' \
'awk -v i=1 "BEGIN {print \"str\" ++i}"' \
"str2\n" \
'' \
'anything'
# gawk compat: FS regex matches only non-empty separators:
# with -*, the splitting is NOT f o o b a r, but foo bar:
testing 'awk FS regex which can match empty string' \
"awk -F '-*' '{print \$1 \"-\" \$2 \"=\" \$3 \"*\" \$4}'" \
"foo-bar=*\n" \
'' \
'foo--bar'
# last+1 field should be empty (had a bug where it wasn't)
testing 'awk $NF is empty' \
"awk -F '=+' '{print \$NF}'" \
"\n" \
'' \
'a=====123='
testing "awk exit N propagates through END's exit" \
"awk 'BEGIN { exit 42 } END { exit }'; echo \$?" \
"42\n" \
'' ''
testing "awk print + redirect" \
"awk 'BEGIN { print \"STDERR %s\" >\"/dev/stderr\" }' 2>&1" \
"STDERR %s\n" \
'' ''
testing "awk \"cmd\" | getline" \
"awk 'BEGIN { \"echo HELLO\" | getline; print }'" \
"HELLO\n" \
'' ''
# printf %% should print one % (had a bug where it didn't)
testing 'awk printf %% prints one %' \
"awk 'BEGIN { printf \"%%\n\" }'" \
"%\n" \
'' ''
exit $FAILCOUNT