1 dnl Copyright © 2021-2023 Nick Bowler
3 dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2.
4 dnl This is free software: you are free to do what the fuck you want to.
5 dnl There is NO WARRANTY, to the extent permitted by law.
7 AT_BANNER([Script tests])
9 m4_define([TEST_GEN_OPTIONS],
10 [AT_KEYWORDS([gen-options awk script scripts])dnl
11 AT_DATA([m4_default([$2], [options.def])], [$1])
12 AT_CHECK([$AWK -f "$srcdir/scripts/gen-options.awk" dnl
13 <m4_default([$2], [options.def]) >options.h])])
15 m4_define([TEST_GEN_OPTIONS_SAMPLE],
18 --option-with-flagval (&x, 5)
21 --option-with-optional-arg[=OPTIONAL]
24 -a, --option-with-sopt
26 -b, --option-with-sopt-and-arg=SOPTARG
27 -c, --option-with-sopt-and-optional-arg[=SOPTOPTIONAL]
28 --option-with-arg-and-val=ARGVAL (42)
29 --option-with-arg-and-flagval=ARGFLAGVAL (&a[1], 'x')
30 --option-with-optional-arg-and-val[=OPTIONALARGVAL] (54)
31 --option-with-optional-arg-and-flagval[=OPTIONALFLAGVAL] (0, 0)
34 that has a line randomly indented
43 AT_SETUP([gen-options.awk])
44 TEST_GEN_OPTIONS([TEST_GEN_OPTIONS_SAMPLE])
47 [[struct option { const char *name; int has_arg; int *flag; int val; };
53 [[#include "context.h"
56 static const char sopts[] = SOPT_STRING;
57 static const struct option opts[] = { LOPTS_INITIALIZER, {0} };
64 AT_CHECK([$CC -o test0$EXEEXT test0.c && ./test0$EXEEXT], [0], [], [ignore])
66 # test 1: long option names and help text
74 static const struct option opts[] = { LOPTS_INITIALIZER };
80 for (i = 0; i < sizeof opts / sizeof opts[0]; i++) {
81 struct lopt_help help = { "INVALID", "INVALID" };
83 if (!lopt_get_help(&opts[i], &help))
86 printf("--%s", opts[i].name);
88 printf("=%s", help.arg);
89 printf("\n%s", help.desc);
98 AT_DATA([lopthelp.awk],
103 if (sub(/\@:>@$/, "", $1))
104 sub(/\@<:@/, "", $1);
110 { sub(/^[ \t]*/, ""); }
114 $AWK -f lopthelp.awk options.def >expout
115 AT_CHECK([$CC -o test1$EXEEXT test1.c && ./test1$EXEEXT],
116 [0], [expout], [ignore])
118 # test 2: short option string
128 struct option lopts[] = {LOPTS_INITIALIZER};
131 for (i = 0; i < sizeof SOPT_STRING - 1; i++) {
132 if (SOPT_STRING[i] != ':') {
133 for (j = 0; j < sizeof lopts / sizeof lopts[0]; j++) {
134 if (lopts[j].val == SOPT_STRING[i]) {
135 printf("--%s ", lopts[j].name);
140 putchar(SOPT_STRING[i]);
141 if (SOPT_STRING[i+1] != ':')
148 AT_DATA([soptstr.awk],
153 sopt = substr($1, 2, 1);
154 arg = sub(/\@:>@$/, "", $2);
155 arg += sub(/\@<:@?=.*$/, "", $2);
157 print $2 " " sopt substr("::", 1, arg);
161 $AWK -f soptstr.awk options.def >expout
162 AT_CHECK([$CC -o test2$EXEEXT test2.c && ./test2$EXEEXT],
163 [0], [expout], [ignore])
167 AT_SETUP([gen-options.awk xgettext annotation])
168 TEST_GEN_OPTIONS([TEST_GEN_OPTIONS_SAMPLE])
170 # Check that all help strings are translatable
171 AT_DATA([messages.awk],
172 [[BEGIN { lines = -1; }
183 if (sub(/\@<:@?=.*/, "", $1)) {
184 arg = substr(tmp, index(tmp, "=")+1);
185 sub(/\@:>@$/, "", arg);
189 ctxt=("msgctxt \"" $1 "\" msgid");
192 print ctxt, ("\"" arg "\"");
196 { sub(/^[ \t]*/, ""); }
198 gsub(/"/, "\\\"", $0);
206 for (i = 0; i < lines; i++) {
207 nl = (i+1 < lines ? "\\n" : "");
208 printf(" \"%s%s\"", help[i], nl);
217 dnl Antique versions of xgettext which predate the pgettext/msgctx feature
218 dnl will produce an output po file with no msgctx lines. So try to spot
219 dnl that and skip the test with such versions.
220 AT_CHECK([xgettext --keyword=PN_:1c,2 options.h
221 test -f messages.po || exit 77
222 grep msgid messages.po >/dev/null &&
223 { grep msgctx messages.po >/dev/null || exit 77; }])
225 $AWK -f messages.awk options.def | LC_ALL=C sort >expout
226 AT_CHECK([sed -n '/^msgctxt/{
237 }' messages.po | LC_ALL=C sort], [0], [expout])
241 AT_SETUP([gen-options.awk packed format])
243 AT_DATA([test.c], [[#include <stdio.h>
244 struct option { const char *name; int has_arg; int *flag; int val; };
248 static unsigned opts[] = { LOPTS_PACKED_INITIALIZER };
256 #elif LOPT_PACK_BITS <= 8
258 #elif LOPT_PACK_BITS <= 16
260 #elif LOPT_PACK_BITS <= 32
267 for (i = 0; i < sizeof opts / sizeof opts[0]; i++) {
270 LOPT_UNPACK(o, opts[i]);
271 printf("--%s, %d, ", o.name, o.has_arg);
272 if (o.val > UCHAR_MAX)
273 printf("%d\n", o.val - UCHAR_MAX - 1);
275 printf("'%c'\n", o.val);
281 TEST_GEN_OPTIONS([[--single-option
283 AT_CHECK([$CC -o single$EXEEXT test.c && ./single$EXEEXT], [0],
285 --single-option, 0, 0
288 TEST_GEN_OPTIONS([[-a, --the-first-option
289 -b, --the-second-option=ARG
290 -c, --the-third-option[=ARG]
291 -d, --the-fourth-option
293 AT_CHECK([$CC -o 16bit$EXEEXT test.c && ./16bit$EXEEXT], [0],
295 --the-first-option, 0, 'a'
296 --the-second-option, 1, 'b'
297 --the-third-option, 2, 'c'
298 --the-fourth-option, 0, 'd'
303 AT_SETUP([gen-strtab.awk])
304 AT_KEYWORDS([gen-strtab awk script scripts])
329 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test.def >test.h])
331 sed -n 's/^[[&]]\([[^ ]]*\).*/\1/p' test.def >identifiers
333 # test 0: sanity test
342 while read id; do AS_ECHO([' printf("%s\n---\n", strtab+'"$id"');']); done
343 AS_ECHO([' return 0;'])
345 } <identifiers >test0.c
347 AT_CHECK([$CC -o test0$EXEEXT test0.c && ./test0$EXEEXT], [0], [---
382 AT_SETUP([gen-strtab.awk @nozero option])
383 AT_KEYWORDS([gen-strtab awk script scripts])
388 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test0.def >test0.h])
394 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test1.def >test1.h])
399 int main(void) { printf("%d %s\n", hello, strtab+hello); return 0; }
401 AT_CHECK([$CC -DHEADER='"test0.h"' -o test0$EXEEXT test.c && ./test0$EXEEXT],
404 AT_CHECK([$CC -DHEADER='"test1.h"' -o test1$EXEEXT test.c && ./test1$EXEEXT],
410 AT_SETUP([gen-strtab.awk @macro option])
411 AT_KEYWORDS([gen-strtab awk script scripts])
419 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test0.def >test0.h])
423 extern const char strtab[];
428 static const char mystrtab[] = STRTAB_INITIALIZER;
429 printf("%s\n%s\n%s\n", mystrtab+foo, mystrtab+bar, mystrtab+baz);
433 AT_CHECK([$CC -o test0$EXEEXT test0.c && ./test0$EXEEXT], [0],
441 AT_SETUP([gen-strtab.awk l10n options])
442 AT_KEYWORDS([gen-strtab awk script scripts])
444 AT_DATA([l10n.sed], dnl (
446 s/.*N_(\([^)]*\)).*/\1/p
454 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test0.def >test0.h])
455 AT_CHECK([sed -n -f l10n.sed test0.h | LC_ALL=C sort], [0],
466 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test1.def >test1.h])
467 AT_CHECK([sed -n -f l10n.sed test1.h], [0],
477 printf("%s %s %s\n", strtab+a, strtab+b, strtab+c);
482 AT_CHECK([$CC -DHEADER='"test0.h"' -o test0$EXEEXT test.c && ./test0$EXEEXT],
483 [0], [[hello world world goodbye
486 AT_CHECK([$CC -DHEADER='"test1.h"' -o test1$EXEEXT test.c && ./test1$EXEEXT],
487 [0], [[hello world world goodbye
493 AT_SETUP([gen-tree.awk])
494 AT_KEYWORDS([gen-tree awk script scripts])
521 AT_CHECK([$AWK -f "$srcdir/scripts/gen-tree.awk" <tree.def >tree.h])
527 struct tree { unsigned id, subtree; };
529 static const struct tree tree0[] = {
532 static const struct tree tree1[] = {
536 void print_subtree(const struct tree *root, unsigned offset, int depth)
538 const struct tree *node;
540 for (node = &root[offset]; node->id; node++) {
541 printf("%*s%s", 2*depth, "", &tree_strtab[node->id]);
543 printf(", %s_OFFSET\n", &tree_strtab[node->id]);
544 print_subtree(root, node->subtree, depth+1);
554 print_subtree(tree0, 0, 1);
556 print_subtree(tree1, 0, 1);
560 sed '/^#/d' tree.def >expout
561 AT_CHECK([$CC -o test0$EXEEXT test0.c && ./test0$EXEEXT], [0], [expout])
565 # Test the gen-tree features that avoid creating string labels for nodes.
566 AT_SETUP([gen-tree.awk @nostrtab option])
567 AT_KEYWORDS([gen-tree awk script scripts])
579 AT_CHECK([$AWK -f "$srcdir/scripts/gen-tree.awk" <tree.def >tree.h])
582 [[float tree_strtab = 0;
591 static struct { int num, offset; } root[] = { ROOT_INITIALIZER };
596 for (i = 0; i < sizeof root / sizeof root[0]; i++) {
597 printf("%d, %d\n", root[i].num, root[i].offset);
603 AT_CHECK([$CC -o test0$EXEEXT test0.c && ./test0$EXEEXT], [0],
622 AT_CHECK([$AWK -f "$srcdir/scripts/gen-tree.awk" <flat.def >flat.h])
624 sed -e 's/tree\.h/flat.h/' -e 's/ROOT/FLAT/' test0.c >test1.c
625 AT_CHECK([$CC -o test1$EXEEXT test1.c && ./test1$EXEEXT], [0],
635 AT_KEYWORDS([join awk script scripts])
637 JOIN="$AWK -f $srcdir/scripts/join.awk --"
664 AT_CHECK([$JOIN a b], [0],
675 AT_CHECK([$JOIN -v1 a b], [0],
683 AT_CHECK([$JOIN -v2 a b], [0],
690 AT_CHECK([$JOIN -v1 -v2 a b], [0],
702 AT_CHECK([$JOIN -a1 a b], [0],
718 AT_CHECK([$JOIN -a2 a b], [0],
733 AT_CHECK([$JOIN -a1 -a2 a b], [0],
753 AT_CHECK([$JOIN b a], [0],
764 AT_CHECK([$JOIN -v1 b a], [0],
771 AT_CHECK([$JOIN -v2 b a], [0],
779 AT_CHECK([$JOIN -v1 -v2 b a], [0],
791 AT_CHECK([$JOIN -a1 b a], [0],
806 AT_CHECK([$JOIN -a2 b a], [0],
822 AT_CHECK([$JOIN -a1 -a2 b a], [0],
842 AT_CHECK([echo wat | $JOIN -v1 - /dev/null], [0],
848 m4_divert_push([PREPARE_TESTS])dnl
850 $PERL -e 'my $x = 42; exit $x;'; test $? = 42 || exit 77
851 $PERL "$srcdir/scripts/fix-ltdl.pl" "$@"
854 $PERL -e 'my $x = 42; exit $x;'; test $? = 42 || exit 77
855 $PERL "$srcdir/scripts/fix-gnulib.pl" "$@"
862 "/^## begin gnulib module $arg/,/^## end gnulib module $arg/p" \
863 "$srcdir/tests/data/gnulib.mk"
866 m4_divert_pop([PREPARE_TESTS])
868 AT_SETUP([fix-gnulib.pl SED_HEADER variables])
869 AT_KEYWORDS([fix-gnulib perl script scripts])
871 test_gnulib_mk gen-header >test.mk.in
872 AT_CHECK([grep SED_HEADER test.mk.in >expout || exit 99])
873 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
874 grep SED_HEADER test.mk], [0], [expout])
878 AT_SETUP([fix-gnulib.pl %reldir% substitution])
879 AT_KEYWORDS([fix-gnulib perl script scripts])
881 test_gnulib_mk sys_types >test.mk.in
882 AT_CHECK([grep '%reldir%' test.mk.in >/dev/null || exit 99])
884 sed -n <test.mk.in >expout '
888 /^## begin gnulib/,/^## end gnulib/!b
893 s|(srcdir)|(top_srcdir)|
895 s|BUILT_SOURCES|gnulib_core_headers|
903 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
904 sed -n -e '/^## begin gnulib/,/^## end gnulib/p' \
905 -e '/CLEANFILES/p' test.mk],
910 AT_SETUP([fix-gnulib.pl warning removal])
911 AT_KEYWORDS([fix-gnulib perl script scripts])
913 AT_DATA([test.mk.in], [[
915 noinst_LTLIBRARIES += libgnu.la
916 libgnu_la_CFLAGS = $(AM_CFLAGS) $(GL_CFLAG_GNULIB_WARNINGS)
917 noinst_LIBRARIES += libgnu.a
918 libgnu_a_CFLAGS = $(AM_CFLAGS) $(GL_CFLAG_GNULIB_WARNINGS)
921 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
922 sed -n '/^## test begin/,/^## test end/p' test.mk], [0], [## test begin
923 EXTRA_LTLIBRARIES += libgnu.la
924 EXTRA_LIBRARIES += libgnu.a
930 AT_SETUP([fix-gnulib.pl header directory creation])
931 AT_KEYWORDS([fix-gnulib perl script scripts])
933 AT_DATA([extract.sed],
949 test_gnulib_mk alloca-opt sys_types stddef >test.mk.in
950 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
951 sed -n -f extract.sed test.mk], [0],
953 $(AM_V_GEN)$(MKDIR_P) lib
956 $(AM_V_GEN)$(MKDIR_P) lib/sys
959 $(AM_V_GEN)$(MKDIR_P) lib
965 dnl TEST_FIND_AUTOMAKE_VER([to-check], [test-action])
967 dnl For each whitespace-separated version token in to-check, check if we can
968 dnl run the programs automake-VER and aclocal-VER. The special token 'default'
969 dnl also checks the unversioned automake and aclocal (or, if set in the
970 dnl environment, $AUTOMAKE and $ACLOCAL).
972 dnl Then test-action is expanded such that shell variables $ac and $am refer to
973 dnl the aclocal and automake programs, and $amver is the actual version
974 dnl reported by --version. The action should do nothing if the version is
975 dnl acceptable, or "continue" if the version is unacceptable.
977 dnl If an acceptable version is found, the AUTOMAKE and ACLOCAL environment
978 dnl variables are set accordingly. Otherwise, the test group is skipped.
979 m4_define([TEST_FIND_AUTOMAKE],
983 [default], [ac=${ACLOCAL-aclocal} am=${AUTOMAKE-automake}],
984 [ac=aclocal-$am; am=automake-$am])
985 amver=`$am --version | sed -n '1s/.* //p'`
986 acver=`$ac --version | sed -n '1s/.* //p'`
987 set x $amver $acver; shift; test x"$[]#" = x"2" || continue
988 test x"$amver" = x"$acver" || continue
992 AT_CHECK([$have_am || exit 77])
993 AUTOMAKE=$am; export AUTOMAKE
994 ACLOCAL=$ac; export ACLOCAL
995 AT_CHECK([$ACLOCAL --version && $AUTOMAKE --version], [0], [stdout])
998 m4_define([TEST_LTDL_LIBOBJ_MANGLING],
999 [TEST_CONFIGURE_AC([[AM_INIT_AUTOMAKE([foreign subdir-objects])
1002 AC_SUBST([ltdl_LTLIBOBJS], [libltdl/test.lo])
1003 AC_CONFIG_FILES([Makefile])
1007 AT_DATA([ltdl.mk.in], [[
1008 AM_CPPFLAGS += -DSTRING=\"helloworld\"
1010 noinst_LTLIBRARIES = libltdl/libltdl.la
1011 libltdl_libltdl_la_SOURCES = libltdl/ltdl.c
1012 libltdl_libltdl_la_LIBADD = $(ltdl_LTLIBOBJS)
1013 libltdl_libltdl_la_DEPENDENCIES = $(ltdl_LTLIBOBJS)
1015 EXTRA_DIST += libltdl/test.c
1017 AT_DATA([Makefile.am], [[AM_CPPFLAGS =
1018 include $(top_srcdir)/ltdl.mk
1019 AM_LIBTOOLFLAGS = --quiet
1022 test_LDADD = libltdl/libltdl.la
1023 all-local: ; @printf '%s\n' $(AM_CPPFLAGS)
1025 AT_DATA([libltdl/test.c], [[#include <stdio.h>
1026 int foo(void) { printf("%s\n", STRING); return 0; }
1028 AT_DATA([libltdl/ltdl.c], [[int foo(void); int main(void) { return foo(); }
1031 AT_CHECK([test_fix_ltdl -i ltdl.mk.in -o ltdl.mk])
1032 libtoolize; TEST_AUTORECONF
1033 TEST_CONFIGURE([--disable-shared])
1034 AT_CHECK([make -s && ./test], [0], [
1038 AT_SETUP([fix-ltdl.pl LIBOBJ mangling (<automake-1.16)])
1039 AT_KEYWORDS([fix-ltdl perl script scripts])
1041 TEST_FIND_AUTOMAKE([default 1.10 1.11 1.12 1.13 1.14 1.15],
1042 [AS_VERSION_COMPARE(["$amver"], [1.16], [], [continue], [continue])])
1043 TEST_LTDL_LIBOBJ_MANGLING
1047 AT_SETUP([fix-ltdl.pl LIBOBJ mangling (>=automake-1.16)])
1048 AT_KEYWORDS([fix-ltdl perl script scripts])
1050 TEST_FIND_AUTOMAKE([default 1.16 1.17 1.18 1.19],
1051 [AS_VERSION_COMPARE(["$amver"], [1.16], [continue])])
1052 TEST_LTDL_LIBOBJ_MANGLING