1 # Copyright © 2021-2024 Nick Bowler
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation, either version 3 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program. If not, see <https://www.gnu.org/licenses/>.
16 AT_BANNER([Script tests])
18 m4_define([TEST_DUMP_PO],
19 [[sed -n '/^msg[ic][td][x ]/{
30 }' messages.po | LC_ALL=C sort]])
32 AT_SETUP([bake-config.awk])
33 AT_KEYWORDS([bake-config awk script scripts])
37 /* #undef HAVE_STUFF */
38 #define HAVE_OTHER_STUFF 1
39 /* #undef HAVE_CRAZY_STUFF */
45 #elif HAVE_CRAZY_STUFF
47 #elif HAVE_OTHER_STUFF
52 AT_CHECK([$AWK -f "$srcdir/scripts/bake-config.awk" cfg.h lib.h], [0],
53 [[#if 0 /* HAVE_STUFF */
55 #elif 0 /* HAVE_CRAZY_STUFF */
56 # define foo world /* hello */
57 #elif 1 /* HAVE_OTHER_STUFF */
64 m4_define([TEST_GEN_OPTIONS],
65 [AT_KEYWORDS([gen-options awk script scripts])dnl
66 AT_DATA([m4_default([$2], [options.def])], [$1])
67 AT_CHECK([$AWK -f "$srcdir/scripts/gen-options.awk" dnl
68 <m4_default([$2], [options.def]) >options.h])])
70 m4_define([TEST_GEN_OPTIONS_SAMPLE],
73 --option-with-flagval (&x, 5)
76 --option-with-optional-arg[=OPTIONAL]
79 -a, --option-with-sopt
81 -b, --option-with-sopt-and-arg=SOPTARG
82 -c, --option-with-sopt-and-optional-arg[=SOPTOPTIONAL]
83 --option-with-arg-and-val=ARGVAL (42)
84 --option-with-arg-and-flagval=ARGFLAGVAL (&a[1], 'x')
85 --option-with-optional-arg-and-val[=OPTIONALARGVAL] (54)
86 --option-with-optional-arg-and-flagval[=OPTIONALFLAGVAL] (0, 0)
89 that has a line randomly indented
98 AT_SETUP([gen-options.awk])
99 TEST_GEN_OPTIONS([TEST_GEN_OPTIONS_SAMPLE])
102 [[struct option { const char *name; int has_arg; int *flag; int val; };
106 # test 0: sanity test
108 [[#include "context.h"
111 static const char sopts[] = SOPT_STRING;
112 static const struct option opts[] = { LOPTS_INITIALIZER, {0} };
119 AT_CHECK([$CC -o test0$EXEEXT test0.c 1>&2 && ./test0$EXEEXT],
122 # test 1: long option names and help text
130 static const struct option opts[] = { LOPTS_INITIALIZER };
136 for (i = 0; i < sizeof opts / sizeof opts[0]; i++) {
137 struct lopt_help help = { "INVALID", "INVALID" };
139 if (!lopt_get_help(&opts[i], &help))
142 printf("--%s", opts[i].name);
144 printf("=%s", help.arg);
145 printf("\n%s", help.desc);
154 AT_DATA([lopthelp.awk],
159 if (sub(/\@:>@$/, "", $1))
160 sub(/\@<:@/, "", $1);
166 { sub(/^[ \t]*/, ""); }
170 $AWK -f lopthelp.awk options.def >expout
171 AT_CHECK([$CC -o test1$EXEEXT test1.c 1>&2 && ./test1$EXEEXT],
172 [0], [expout], [ignore])
174 # test 2: short option string
184 struct option lopts[] = {LOPTS_INITIALIZER};
187 for (i = 0; i < sizeof SOPT_STRING - 1; i++) {
188 if (SOPT_STRING[i] != ':') {
189 for (j = 0; j < sizeof lopts / sizeof lopts[0]; j++) {
190 if (lopts[j].val == SOPT_STRING[i]) {
191 printf("--%s ", lopts[j].name);
196 putchar(SOPT_STRING[i]);
197 if (SOPT_STRING[i+1] != ':')
204 AT_DATA([soptstr.awk],
209 sopt = substr($1, 2, 1);
210 arg = sub(/\@:>@$/, "", $2);
211 arg += sub(/\@<:@?=.*$/, "", $2);
213 print $2 " " sopt substr("::", 1, arg);
217 $AWK -f soptstr.awk options.def >expout
218 AT_CHECK([$CC -o test2$EXEEXT test2.c 1>&2 && ./test2$EXEEXT],
219 [0], [expout], [ignore])
223 AT_SETUP([gen-options.awk xgettext annotation])
224 TEST_GEN_OPTIONS([TEST_GEN_OPTIONS_SAMPLE])
226 # Check that all help strings are translatable
227 AT_DATA([messages.awk],
228 [[BEGIN { lines = -1; }
239 if (sub(/\@<:@?=.*/, "", $1)) {
240 arg = substr(tmp, index(tmp, "=")+1);
241 sub(/\@:>@$/, "", arg);
245 ctxt=("msgctxt \"" $1 "\" msgid");
248 print ctxt, ("\"" arg "\"");
252 { sub(/^[ \t]*/, ""); }
254 gsub(/"/, "\\\"", $0);
261 printf "%s", (lines > 0 ? "msgid" : ctxt);
262 for (i = 0; i < lines; i++) {
263 nl = (i+1 < lines ? "\\n" : "");
264 printf(" \"%s%s\"", help[i], nl);
273 dnl Antique versions of xgettext which predate the pgettext/msgctx feature
274 dnl will produce an output po file with no msgctx lines. So try to spot
275 dnl that and skip the test with such versions.
276 AT_CHECK([xgettext --omit-header options.h
277 test -f messages.po || exit 77
278 grep msgid messages.po >/dev/null &&
279 { grep msgctx messages.po >/dev/null || exit 77; }])
281 $AWK -f messages.awk options.def | LC_ALL=C sort >expout
282 AT_CHECK([TEST_DUMP_PO], [0], [expout])
286 AT_SETUP([gen-options.awk packed format])
288 AT_DATA([test.c], [[#include <stdio.h>
289 struct option { const char *name; int has_arg; int *flag; int val; };
293 static unsigned opts[] = { LOPTS_PACKED_INITIALIZER };
301 #elif LOPT_PACK_BITS <= 8
303 #elif LOPT_PACK_BITS <= 16
305 #elif LOPT_PACK_BITS <= 32
312 for (i = 0; i < sizeof opts / sizeof opts[0]; i++) {
315 LOPT_UNPACK(o, opts[i]);
316 printf("--%s, %d, ", o.name, o.has_arg);
317 if (o.val > UCHAR_MAX)
318 printf("%d\n", o.val - UCHAR_MAX - 1);
320 printf("'%c'\n", o.val);
326 TEST_GEN_OPTIONS([[--single-option
328 AT_CHECK([$CC -o single$EXEEXT test.c 1>&2 && ./single$EXEEXT], [0],
330 --single-option, 0, 0
333 TEST_GEN_OPTIONS([[-a, --the-first-option
334 -b, --the-second-option=ARG
335 -c, --the-third-option[=ARG]
336 -d, --the-fourth-option
338 AT_CHECK([$CC -o 16bit$EXEEXT test.c 1>&2 && ./16bit$EXEEXT], [0],
340 --the-first-option, 0, 'a'
341 --the-second-option, 1, 'b'
342 --the-third-option, 2, 'c'
343 --the-fourth-option, 0, 'd'
348 AT_SETUP([gen-strtab.awk])
349 AT_KEYWORDS([gen-strtab awk script scripts])
372 &k with nontrivial whitespace
375 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test.def >test.h])
377 sed -n 's/^[[&]]\([[^ ]]*\).*/\1/p' test.def >identifiers
379 # test 0: sanity test
388 while read id; do AS_ECHO([' printf("%s\n---\n", strtab+'"$id"');']); done
389 AS_ECHO([' return 0;'])
391 } <identifiers >test0.c
393 AT_CHECK([$CC -o test0$EXEEXT test0.c 1>&2 && ./test0$EXEEXT], [0], [---
424 with nontrivial whitespace
430 AT_SETUP([gen-strtab.awk @nozero option])
431 AT_KEYWORDS([gen-strtab awk script scripts])
437 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test0.def >test0.h])
444 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test1.def >test1.h])
450 printf("%d \"%s\"\n", hello, strtab+hello);
451 printf("%d \"%s\"\n", empty, strtab+empty);
452 printf("%d %d\n", (int)sizeof strtab, STRTAB_MAX_OFFSET);
456 AT_CHECK([$CC -DHEADER='"test0.h"' -o test0$EXEEXT test.c 1>&2 &&
457 ./test0$EXEEXT], [0], [[0 "hello"
461 AT_CHECK([$CC -DHEADER='"test1.h"' -o test1$EXEEXT test.c 1>&2 &&
462 ./test1$EXEEXT], [0], [[1 "hello"
469 AT_SETUP([gen-strtab.awk @macro option])
470 AT_KEYWORDS([gen-strtab awk script scripts])
478 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test0.def >test0.h])
487 static const char mystrtab[] = STRTAB_INITIALIZER;
488 printf("%s\n%s\n%s\n", mystrtab+foo, mystrtab+bar, mystrtab+baz);
492 AT_CHECK([$CC -o test0$EXEEXT test0.c 1>&2 && ./test0$EXEEXT], [0],
500 AT_SETUP([gen-strtab.awk l10n options])
501 AT_KEYWORDS([gen-strtab awk script scripts])
503 AT_DATA([xgettext.sed], dnl (
505 s/.*gettext(\([^)]*\)).*/msgid \1\
514 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test0.def >test0.h])
515 AT_CHECK([rm -f messages.po; xgettext --omit-header test0.h
516 test -f messages.po || sed -n -f xgettext.sed test0.h >messages.po
528 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test1.def >test1.h])
529 AT_CHECK([rm -f messages.po; xgettext --omit-header test1.h
530 test -f messages.po || sed -n -f xgettext.sed test1.h >messages.po
532 [[msgid "hello world"
541 printf("%s %s %s\n", strtab+a, strtab+b, strtab+c);
546 AT_CHECK([$CC -DHEADER='"test0.h"' -o test0$EXEEXT test.c 1>&2 &&
547 ./test0$EXEEXT], [0], [[hello world world goodbye
550 AT_CHECK([$CC -DHEADER='"test1.h"' -o test1$EXEEXT test.c 1>&2 &&
551 ./test1$EXEEXT], [0], [[hello world world goodbye
556 AT_SETUP([gen-strtab.awk numeric strings])
557 AT_KEYWORDS([gen-strtab awk script scripts])
565 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test0.def >test0.h])
574 static const char mystrtab[16] = STRTAB_INITIALIZER;
575 printf("%s\n%s\n%s\n", mystrtab+A, mystrtab+B, mystrtab+C);
579 AT_CHECK([$CC -o test0$EXEEXT test0.c 1>&2 && ./test0$EXEEXT], [0],
587 AT_SETUP([gen-strtab.awk numeric escapes])
588 AT_KEYWORDS([gen-strtab awk script scripts])
599 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test0.def >test0.h])
608 static const char mystrtab[] = STRTAB_INITIALIZER;
610 printf("%d\n", (int)sizeof mystrtab);
611 printf("%d %d %d %d %d %d\n", A, B, C, D, E, F);
612 printf("%d\n", mystrtab[0] == 1);
616 AT_CHECK([$CC -o test0$EXEEXT test0.c 1>&2 && ./test0$EXEEXT], [0],
629 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test1.def >test1.h])
638 static const char mystrtab[] = STRTAB_INITIALIZER;
640 printf("%d\n", (int)sizeof mystrtab);
641 printf("%d%d %d%d %d%d\n", mystrtab[A] == '\1', mystrtab[A+1] == 0,
642 mystrtab[B] == '\120', mystrtab[B+1] == 0,
643 mystrtab[C] == '\377', mystrtab[C+1] == 0);
644 printf("%d\n", B == D);
648 AT_CHECK([$CC -o test1$EXEEXT test1.c 1>&2 && ./test1$EXEEXT], [0],
656 AT_SETUP([gen-tree.awk])
657 AT_KEYWORDS([gen-tree awk script scripts])
684 AT_CHECK([$AWK -f "$srcdir/scripts/gen-tree.awk" <tree.def >tree.h])
690 struct tree { unsigned id, subtree; };
692 static const struct tree tree0[] = {
695 static const struct tree tree1[] = {
699 void print_subtree(const struct tree *root, unsigned offset, int depth)
701 const struct tree *node;
703 for (node = &root[offset]; node->id; node++) {
704 printf("%*s%s", 2*depth, "", &tree_strtab[node->id]);
706 printf(", %s_OFFSET\n", &tree_strtab[node->id]);
707 print_subtree(root, node->subtree, depth+1);
717 print_subtree(tree0, 0, 1);
719 print_subtree(tree1, 0, 1);
723 sed '/^#/d' tree.def >expout
724 AT_CHECK([$CC -o test0$EXEEXT test0.c 1>&2 && ./test0$EXEEXT],
725 [0], [expout], [ignore])
729 # Test the gen-tree features that avoid creating string labels for nodes.
730 AT_SETUP([gen-tree.awk @nostrtab option])
731 AT_KEYWORDS([gen-tree awk script scripts])
743 AT_CHECK([$AWK -f "$srcdir/scripts/gen-tree.awk" <tree.def >tree.h])
746 [[float tree_strtab = 0;
755 static struct { int num, offset; } root[] = { ROOT_INITIALIZER };
760 for (i = 0; i < sizeof root / sizeof root[0]; i++) {
761 printf("%d, %d\n", root[i].num, root[i].offset);
767 AT_CHECK([$CC -o test0$EXEEXT test0.c 1>&2 && ./test0$EXEEXT], [0],
786 AT_CHECK([$AWK -f "$srcdir/scripts/gen-tree.awk" <flat.def >flat.h])
788 sed -e 's/tree\.h/flat.h/' -e 's/ROOT/FLAT/' test0.c >test1.c
789 AT_CHECK([$CC -o test1$EXEEXT test1.c 1>&2 && ./test1$EXEEXT], [0],
799 AT_KEYWORDS([join awk script scripts])
801 JOIN="$AWK -f $srcdir/scripts/join.awk --"
828 AT_CHECK([$JOIN a b], [0],
839 AT_CHECK([$JOIN -v1 a b], [0],
847 AT_CHECK([$JOIN -v2 a b], [0],
854 AT_CHECK([$JOIN -v1 -v2 a b], [0],
866 AT_CHECK([$JOIN -a1 a b], [0],
882 AT_CHECK([$JOIN -a2 a b], [0],
897 AT_CHECK([$JOIN -a1 -a2 a b], [0],
917 AT_CHECK([$JOIN b a], [0],
928 AT_CHECK([$JOIN -v1 b a], [0],
935 AT_CHECK([$JOIN -v2 b a], [0],
943 AT_CHECK([$JOIN -v1 -v2 b a], [0],
955 AT_CHECK([$JOIN -a1 b a], [0],
970 AT_CHECK([$JOIN -a2 b a], [0],
986 AT_CHECK([$JOIN -a1 -a2 b a], [0],
1006 AT_CHECK([echo wat | $JOIN -v1 - /dev/null], [0],
1012 m4_divert_push([PREPARE_TESTS])dnl
1014 $PERL -e 'my $x = 42; exit $x;'; test $? = 42 || exit 77
1015 $PERL "$srcdir/scripts/fix-ltdl.pl" "$@"
1017 test_fix_gnulib () {
1018 $PERL -e 'my $x = 42; exit $x;'; test $? = 42 || exit 77
1019 $PERL "$srcdir/scripts/fix-gnulib.pl" "$@"
1026 "/^## begin gnulib module $arg/,/^## end gnulib module $arg/p" \
1027 "$srcdir/tests/data/gnulib.mk"
1030 m4_divert_pop([PREPARE_TESTS])
1032 AT_SETUP([fix-gnulib.pl SED_HEADER variables])
1033 AT_KEYWORDS([fix-gnulib perl script scripts])
1035 test_gnulib_mk gen-header >test.mk.in
1036 AT_CHECK([grep SED_HEADER test.mk.in >expout || exit 99])
1037 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
1038 grep SED_HEADER test.mk], [0], [expout])
1042 AT_SETUP([fix-gnulib.pl warning removal])
1043 AT_KEYWORDS([fix-gnulib perl script scripts])
1045 AT_DATA([test.mk.in], [[
1047 noinst_LTLIBRARIES += libgnu.la
1048 libgnu_la_CFLAGS = $(AM_CFLAGS) $(GL_CFLAG_GNULIB_WARNINGS)
1049 noinst_LIBRARIES += libgnu.a
1050 libgnu_a_CFLAGS = $(AM_CFLAGS) $(GL_CFLAG_GNULIB_WARNINGS)
1053 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
1054 sed -n '/^## test begin/,/^## test end/p' test.mk], [0], [## test begin
1055 EXTRA_LTLIBRARIES += libgnu.la
1056 EXTRA_LIBRARIES += libgnu.a
1062 AT_SETUP([fix-gnulib.pl header directory creation])
1063 AT_KEYWORDS([fix-gnulib perl script scripts])
1065 AT_DATA([extract.awk],
1066 [[$0 !~ /^\t/ && $1 ~ /:$/ {
1069 for (i = 2; i <= NF; i++) {
1070 if ($i ~ /am__dirstamp/)
1071 target = target " " $i;
1077 target != "" && sub(/[$][({](AM_V_GEN|gl_V_at)[})].*$/, "[OK]") {
1084 test_gnulib_mk alloca-opt sys_types stddef >test.mk.in
1085 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
1086 $AWK -f extract.awk test.mk
1087 grep '^EXTRA_PROGRAMS' test.mk | LC_ALL=C sort
1088 $AWK '$[1] ~ /dirstamp_SOURCES/ { print $[1]; }' test.mk | LC_ALL=C sort], [0],
1089 [[lib/alloca.h: lib/$(am__dirstamp) [OK]
1090 lib/sys/types.h: lib/sys/$(am__dirstamp) [OK]
1091 lib/stddef.h: lib/$(am__dirstamp) [OK]
1092 EXTRA_PROGRAMS += lib/gl-dirstamp
1093 EXTRA_PROGRAMS += lib/sys/gl-dirstamp
1094 lib_gl_dirstamp_SOURCES
1095 lib_sys_gl_dirstamp_SOURCES
1100 dnl TEST_FIND_AUTOMAKE_VER([to-check], [test-action])
1102 dnl For each whitespace-separated version token in to-check, check if we can
1103 dnl run the programs automake-VER and aclocal-VER. The special token 'default'
1104 dnl also checks the unversioned automake and aclocal (or, if set in the
1105 dnl environment, $AUTOMAKE and $ACLOCAL).
1107 dnl Then test-action is expanded such that shell variables $ac and $am refer to
1108 dnl the aclocal and automake programs, and $amver is the actual version
1109 dnl reported by --version. The action should do nothing if the version is
1110 dnl acceptable, or "continue" if the version is unacceptable.
1112 dnl If an acceptable version is found, the AUTOMAKE and ACLOCAL environment
1113 dnl variables are set accordingly. Otherwise, the test group is skipped.
1114 m4_define([TEST_FIND_AUTOMAKE],
1118 [default], [ac=${ACLOCAL-aclocal} am=${AUTOMAKE-automake}],
1119 [ac=aclocal-$am; am=automake-$am])
1120 amver=`$am --version | sed -n '1s/.* //p'`
1121 acver=`$ac --version | sed -n '1s/.* //p'`
1122 set x $amver $acver; shift; test x"$[]#" = x"2" || continue
1123 test x"$amver" = x"$acver" || continue
1127 AT_CHECK([$have_am || exit 77])
1128 AUTOMAKE=$am; export AUTOMAKE
1129 ACLOCAL=$ac; export ACLOCAL
1130 AT_CHECK([$ACLOCAL --version && $AUTOMAKE --version], [0], [stdout])
1133 m4_define([TEST_LTDL_LIBOBJ_MANGLING],
1134 [TEST_CONFIGURE_AC([[AM_INIT_AUTOMAKE([foreign subdir-objects])
1137 AC_SUBST([ltdl_LTLIBOBJS], [libltdl/test.lo])
1138 AC_CONFIG_FILES([Makefile])
1142 AT_DATA([ltdl.mk.in], [[
1143 AM_CPPFLAGS += -DSTRING=\"helloworld\"
1145 noinst_LTLIBRARIES = libltdl/libltdl.la
1146 libltdl_libltdl_la_SOURCES = libltdl/ltdl.c
1147 libltdl_libltdl_la_LIBADD = $(ltdl_LTLIBOBJS)
1148 libltdl_libltdl_la_DEPENDENCIES = $(ltdl_LTLIBOBJS)
1150 EXTRA_DIST += libltdl/test.c
1152 AT_DATA([Makefile.am], [[AM_CPPFLAGS =
1153 include $(top_srcdir)/ltdl.mk
1154 AM_LIBTOOLFLAGS = --quiet
1157 test_LDADD = libltdl/libltdl.la
1158 all-local: ; @printf '%s\n' $(AM_CPPFLAGS)
1160 AT_DATA([libltdl/test.c], [[#include <stdio.h>
1161 int foo(void) { printf("%s\n", STRING); return 0; }
1163 AT_DATA([libltdl/ltdl.c], [[int foo(void); int main(void) { return foo(); }
1166 AT_CHECK([test_fix_ltdl -i ltdl.mk.in -o ltdl.mk])
1167 libtoolize; TEST_AUTORECONF
1168 TEST_CONFIGURE([--disable-shared])
1169 AT_CHECK([make -s && ./test], [0], [
1173 AT_SETUP([fix-ltdl.pl LIBOBJ mangling (<automake-1.16)])
1174 AT_KEYWORDS([fix-ltdl perl script scripts])
1176 TEST_FIND_AUTOMAKE([default 1.10 1.11 1.12 1.13 1.14 1.15],
1177 [AS_VERSION_COMPARE(["$amver"], [1.16], [], [continue], [continue])])
1178 TEST_LTDL_LIBOBJ_MANGLING
1182 AT_SETUP([fix-ltdl.pl LIBOBJ mangling (>=automake-1.16)])
1183 AT_KEYWORDS([fix-ltdl perl script scripts])
1185 TEST_FIND_AUTOMAKE([default 1.16 1.17 1.18 1.19],
1186 [AS_VERSION_COMPARE(["$amver"], [1.16], [continue])])
1187 TEST_LTDL_LIBOBJ_MANGLING