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 exec 3<identifiers 4>>test0.c
343 while read ident <&3; do
344 AS_ECHO([' printf("%s\n---\n", '"strtab+$ident);"]) >&4
346 AS_ECHO([' return 0;']) >&4
350 AT_CHECK([$CC -o test0$EXEEXT test0.c && ./test0$EXEEXT], [0], [---
385 AT_SETUP([gen-strtab.awk @nozero option])
386 AT_KEYWORDS([gen-strtab awk script scripts])
391 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test0.def >test0.h])
397 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test1.def >test1.h])
402 int main(void) { printf("%d %s\n", hello, strtab+hello); return 0; }
404 AT_CHECK([$CC -DHEADER='"test0.h"' -o test0$EXEEXT test.c && ./test0$EXEEXT],
407 AT_CHECK([$CC -DHEADER='"test1.h"' -o test1$EXEEXT test.c && ./test1$EXEEXT],
413 AT_SETUP([gen-strtab.awk @macro option])
414 AT_KEYWORDS([gen-strtab awk script scripts])
422 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test0.def >test0.h])
426 extern const char strtab[];
431 static const char mystrtab[] = STRTAB_INITIALIZER;
432 printf("%s\n%s\n%s\n", mystrtab+foo, mystrtab+bar, mystrtab+baz);
436 AT_CHECK([$CC -o test0$EXEEXT test0.c && ./test0$EXEEXT], [0],
444 AT_SETUP([gen-strtab.awk l10n options])
445 AT_KEYWORDS([gen-strtab awk script scripts])
447 AT_DATA([l10n.sed], dnl (
449 s/.*N_(\([^)]*\)).*/\1/p
457 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test0.def >test0.h])
458 AT_CHECK([sed -n -f l10n.sed test0.h | LC_ALL=C sort], [0],
469 AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test1.def >test1.h])
470 AT_CHECK([sed -n -f l10n.sed test1.h], [0],
480 printf("%s %s %s\n", strtab+a, strtab+b, strtab+c);
485 AT_CHECK([$CC -DHEADER='"test0.h"' -o test0$EXEEXT test.c && ./test0$EXEEXT],
486 [0], [[hello world world goodbye
489 AT_CHECK([$CC -DHEADER='"test1.h"' -o test1$EXEEXT test.c && ./test1$EXEEXT],
490 [0], [[hello world world goodbye
496 AT_SETUP([gen-tree.awk])
497 AT_KEYWORDS([gen-tree awk script scripts])
524 AT_CHECK([$AWK -f "$srcdir/scripts/gen-tree.awk" <tree.def >tree.h])
530 struct tree { unsigned id, subtree; };
532 static const struct tree tree0[] = {
535 static const struct tree tree1[] = {
539 void print_subtree(const struct tree *root, unsigned offset, int depth)
541 const struct tree *node;
543 for (node = &root[offset]; node->id; node++) {
544 printf("%*s%s", 2*depth, "", &tree_strtab[node->id]);
546 printf(", %s_OFFSET\n", &tree_strtab[node->id]);
547 print_subtree(root, node->subtree, depth+1);
557 print_subtree(tree0, 0, 1);
559 print_subtree(tree1, 0, 1);
563 sed '/^#/d' tree.def >expout
564 AT_CHECK([$CC -o test0$EXEEXT test0.c && ./test0$EXEEXT], [0], [expout])
568 # Test the gen-tree features that avoid creating string labels for nodes.
569 AT_SETUP([gen-tree.awk @nostrtab option])
570 AT_KEYWORDS([gen-tree awk script scripts])
582 AT_CHECK([$AWK -f "$srcdir/scripts/gen-tree.awk" <tree.def >tree.h])
585 [[float tree_strtab = 0;
594 static struct { int num, offset; } root[] = { ROOT_INITIALIZER };
599 for (i = 0; i < sizeof root / sizeof root[0]; i++) {
600 printf("%d, %d\n", root[i].num, root[i].offset);
606 AT_CHECK([$CC -o test0$EXEEXT test0.c && ./test0$EXEEXT], [0],
625 AT_CHECK([$AWK -f "$srcdir/scripts/gen-tree.awk" <flat.def >flat.h])
627 sed -e 's/tree\.h/flat.h/' -e 's/ROOT/FLAT/' test0.c >test1.c
628 AT_CHECK([$CC -o test1$EXEEXT test1.c && ./test1$EXEEXT], [0],
638 AT_KEYWORDS([join awk script scripts])
640 JOIN="$AWK -f $srcdir/scripts/join.awk --"
667 AT_CHECK([$JOIN a b], [0],
678 AT_CHECK([$JOIN -v1 a b], [0],
686 AT_CHECK([$JOIN -v2 a b], [0],
693 AT_CHECK([$JOIN -v1 -v2 a b], [0],
705 AT_CHECK([$JOIN -a1 a b], [0],
721 AT_CHECK([$JOIN -a2 a b], [0],
736 AT_CHECK([$JOIN -a1 -a2 a b], [0],
756 AT_CHECK([$JOIN b a], [0],
767 AT_CHECK([$JOIN -v1 b a], [0],
774 AT_CHECK([$JOIN -v2 b a], [0],
782 AT_CHECK([$JOIN -v1 -v2 b a], [0],
794 AT_CHECK([$JOIN -a1 b a], [0],
809 AT_CHECK([$JOIN -a2 b a], [0],
825 AT_CHECK([$JOIN -a1 -a2 b a], [0],
845 AT_CHECK([echo wat | $JOIN -v1 - /dev/null], [0],
851 m4_divert_push([PREPARE_TESTS])dnl
853 $PERL -e 'my $x = 42; exit $x;'; test $? = 42 || exit 77
854 $PERL -f "$srcdir/scripts/fix-ltdl.pl" "$@"
857 $PERL -e 'my $x = 42; exit $x;'; test $? = 42 || exit 77
858 $PERL -f "$srcdir/scripts/fix-gnulib.pl" "$@"
864 sed -n -f - "$srcdir/tests/data/gnulib.mk" <<EOF
865 /^## begin gnulib module $arg/,/^## end gnulib module $arg/p
869 m4_divert_pop([PREPARE_TESTS])
871 AT_SETUP([fix-gnulib.pl SED_HEADER variables])
873 test_gnulib_mk gen-header >test.mk.in
874 AT_CHECK([grep SED_HEADER test.mk.in >expout || exit 99])
875 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
876 grep SED_HEADER test.mk], [0], [expout])
880 AT_SETUP([fix-gnulib.pl %reldir% substitution])
882 test_gnulib_mk sys_types >test.mk.in
883 AT_CHECK([grep '%reldir%' test.mk.in >/dev/null || exit 99])
885 sed -n -f - test.mk.in >expout <<'EOF'
887 /^## begin gnulib/,/^## end gnulib/!b
889 s|(srcdir)|(top_srcdir)|
891 s|BUILT_SOURCES|gnulib_core_headers|
893 /^MOSTLYCLEANFILES/{h;b}
897 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
898 sed -n -e '/^## begin gnulib/,/^## end gnulib/p' \
899 -e '/CLEANFILES/p' test.mk],
904 AT_SETUP([fix-gnulib.pl warning removal])
906 AT_DATA([test.mk.in], [[
908 noinst_LTLIBRARIES += libgnu.la
909 libgnu_la_CFLAGS = $(AM_CFLAGS) $(GL_CFLAG_GNULIB_WARNINGS)
910 noinst_LIBRARIES += libgnu.a
911 libgnu_a_CFLAGS = $(AM_CFLAGS) $(GL_CFLAG_GNULIB_WARNINGS)
914 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
915 sed -n '/^## test begin/,/^## test end/p' test.mk], [0], [## test begin
916 EXTRA_LTLIBRARIES += libgnu.la
917 EXTRA_LIBRARIES += libgnu.a
923 AT_SETUP([fix-gnulib.pl header directory creation])
925 AT_DATA([extract.sed],
941 test_gnulib_mk alloca-opt sys_types stddef >test.mk.in
942 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
943 sed -n -f extract.sed test.mk], [0],
945 $(AM_V_GEN)$(MKDIR_P) lib
948 $(AM_V_GEN)$(MKDIR_P) lib/sys
951 $(AM_V_GEN)$(MKDIR_P) lib
957 dnl TEST_FIND_AUTOMAKE_VER([to-check], [test-action])
959 dnl For each whitespace-separated version token in to-check, check if we can
960 dnl run the programs automake-VER and aclocal-VER. The special token 'default'
961 dnl also checks the unversioned automake and aclocal (or, if set in the
962 dnl environment, $AUTOMAKE and $ACLOCAL).
964 dnl Then test-action is expanded such that shell variables $ac and $am refer to
965 dnl the aclocal and automake programs, and $amver is the actual version
966 dnl reported by --version. The action should do nothing if the version is
967 dnl acceptable, or "continue" if the version is unacceptable.
969 dnl If an acceptable version is found, the AUTOMAKE and ACLOCAL environment
970 dnl variables are set accordingly. Otherwise, the test group is skipped.
971 m4_define([TEST_FIND_AUTOMAKE],
975 [default], [ac=${ACLOCAL-aclocal} am=${AUTOMAKE-automake}],
976 [ac=aclocal-$am; am=automake-$am])
977 amver=`$am --version | sed -n '1s/.* //p'`
978 acver=`$ac --version | sed -n '1s/.* //p'`
979 set x $amver $acver; shift; test x"$[]#" = x"2" || continue
980 test x"$amver" = x"$acver" || continue
984 AT_CHECK([$have_am || exit 77])
985 AUTOMAKE=$am; export AUTOMAKE
986 ACLOCAL=$ac; export ACLOCAL
987 AT_CHECK([$ACLOCAL --version && $AUTOMAKE --version], [0], [stdout])
990 m4_define([TEST_LTDL_LIBOBJ_MANGLING],
991 [TEST_CONFIGURE_AC([[AM_INIT_AUTOMAKE([foreign subdir-objects])
994 AC_SUBST([ltdl_LTLIBOBJS], [libltdl/test.lo])
995 AC_CONFIG_FILES([Makefile])
999 AT_DATA([ltdl.mk.in], [[
1000 AM_CPPFLAGS += -DSTRING=\"helloworld\"
1002 noinst_LTLIBRARIES = libltdl/libltdl.la
1003 libltdl_libltdl_la_SOURCES = libltdl/ltdl.c
1004 libltdl_libltdl_la_LIBADD = $(ltdl_LTLIBOBJS)
1005 libltdl_libltdl_la_DEPENDENCIES = $(ltdl_LTLIBOBJS)
1007 EXTRA_DIST += libltdl/test.c
1009 AT_DATA([Makefile.am], [[AM_CPPFLAGS =
1010 include $(top_srcdir)/ltdl.mk
1011 AM_LIBTOOLFLAGS = --quiet
1014 test_LDADD = libltdl/libltdl.la
1015 all-local: ; @printf '%s\n' $(AM_CPPFLAGS)
1017 AT_DATA([libltdl/test.c], [[#include <stdio.h>
1018 int foo(void) { printf("%s\n", STRING); return 0; }
1020 AT_DATA([libltdl/ltdl.c], [[int foo(void); int main(void) { return foo(); }
1023 AT_CHECK([test_fix_ltdl -i ltdl.mk.in -o ltdl.mk])
1024 libtoolize; TEST_AUTORECONF
1025 TEST_CONFIGURE([--disable-shared])
1026 AT_CHECK([make -s && ./test], [0], [
1030 AT_SETUP([fix-ltdl.pl LIBOBJ mangling (<automake-1.16)])
1032 TEST_FIND_AUTOMAKE([default 1.10 1.11 1.12 1.13 1.14 1.15],
1033 [AS_VERSION_COMPARE(["$amver"], [1.16], [], [continue], [continue])])
1034 TEST_LTDL_LIBOBJ_MANGLING
1038 AT_SETUP([fix-ltdl.pl LIBOBJ mangling (>=automake-1.16)])
1040 TEST_FIND_AUTOMAKE([default 1.16 1.17 1.18 1.19],
1041 [AS_VERSION_COMPARE(["$amver"], [1.16], [continue])])
1042 TEST_LTDL_LIBOBJ_MANGLING