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 -f "$srcdir/scripts/fix-ltdl.pl" "$@"
854 $PERL -e 'my $x = 42; exit $x;'; test $? = 42 || exit 77
855 $PERL -f "$srcdir/scripts/fix-gnulib.pl" "$@"
861 sed -n -f - "$srcdir/tests/data/gnulib.mk" <<EOF
862 /^## begin gnulib module $arg/,/^## end gnulib module $arg/p
866 m4_divert_pop([PREPARE_TESTS])
868 AT_SETUP([fix-gnulib.pl SED_HEADER variables])
870 test_gnulib_mk gen-header >test.mk.in
871 AT_CHECK([grep SED_HEADER test.mk.in >expout || exit 99])
872 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
873 grep SED_HEADER test.mk], [0], [expout])
877 AT_SETUP([fix-gnulib.pl %reldir% substitution])
879 test_gnulib_mk sys_types >test.mk.in
880 AT_CHECK([grep '%reldir%' test.mk.in >/dev/null || exit 99])
882 sed -n -f - test.mk.in >expout <<'EOF'
884 /^## begin gnulib/,/^## end gnulib/!b
886 s|(srcdir)|(top_srcdir)|
888 s|BUILT_SOURCES|gnulib_core_headers|
890 /^MOSTLYCLEANFILES/{h;b}
894 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
895 sed -n -e '/^## begin gnulib/,/^## end gnulib/p' \
896 -e '/CLEANFILES/p' test.mk],
901 AT_SETUP([fix-gnulib.pl warning removal])
903 AT_DATA([test.mk.in], [[
905 noinst_LTLIBRARIES += libgnu.la
906 libgnu_la_CFLAGS = $(AM_CFLAGS) $(GL_CFLAG_GNULIB_WARNINGS)
907 noinst_LIBRARIES += libgnu.a
908 libgnu_a_CFLAGS = $(AM_CFLAGS) $(GL_CFLAG_GNULIB_WARNINGS)
911 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
912 sed -n '/^## test begin/,/^## test end/p' test.mk], [0], [## test begin
913 EXTRA_LTLIBRARIES += libgnu.la
914 EXTRA_LIBRARIES += libgnu.a
920 AT_SETUP([fix-gnulib.pl header directory creation])
922 AT_DATA([extract.sed],
938 test_gnulib_mk alloca-opt sys_types stddef >test.mk.in
939 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
940 sed -n -f extract.sed test.mk], [0],
942 $(AM_V_GEN)$(MKDIR_P) lib
945 $(AM_V_GEN)$(MKDIR_P) lib/sys
948 $(AM_V_GEN)$(MKDIR_P) lib
954 dnl TEST_FIND_AUTOMAKE_VER([to-check], [test-action])
956 dnl For each whitespace-separated version token in to-check, check if we can
957 dnl run the programs automake-VER and aclocal-VER. The special token 'default'
958 dnl also checks the unversioned automake and aclocal (or, if set in the
959 dnl environment, $AUTOMAKE and $ACLOCAL).
961 dnl Then test-action is expanded such that shell variables $ac and $am refer to
962 dnl the aclocal and automake programs, and $amver is the actual version
963 dnl reported by --version. The action should do nothing if the version is
964 dnl acceptable, or "continue" if the version is unacceptable.
966 dnl If an acceptable version is found, the AUTOMAKE and ACLOCAL environment
967 dnl variables are set accordingly. Otherwise, the test group is skipped.
968 m4_define([TEST_FIND_AUTOMAKE],
972 [default], [ac=${ACLOCAL-aclocal} am=${AUTOMAKE-automake}],
973 [ac=aclocal-$am; am=automake-$am])
974 amver=`$am --version | sed -n '1s/.* //p'`
975 acver=`$ac --version | sed -n '1s/.* //p'`
976 set x $amver $acver; shift; test x"$[]#" = x"2" || continue
977 test x"$amver" = x"$acver" || continue
981 AT_CHECK([$have_am || exit 77])
982 AUTOMAKE=$am; export AUTOMAKE
983 ACLOCAL=$ac; export ACLOCAL
984 AT_CHECK([$ACLOCAL --version && $AUTOMAKE --version], [0], [stdout])
987 m4_define([TEST_LTDL_LIBOBJ_MANGLING],
988 [TEST_CONFIGURE_AC([[AM_INIT_AUTOMAKE([foreign subdir-objects])
991 AC_SUBST([ltdl_LTLIBOBJS], [libltdl/test.lo])
992 AC_CONFIG_FILES([Makefile])
996 AT_DATA([ltdl.mk.in], [[
997 AM_CPPFLAGS += -DSTRING=\"helloworld\"
999 noinst_LTLIBRARIES = libltdl/libltdl.la
1000 libltdl_libltdl_la_SOURCES = libltdl/ltdl.c
1001 libltdl_libltdl_la_LIBADD = $(ltdl_LTLIBOBJS)
1002 libltdl_libltdl_la_DEPENDENCIES = $(ltdl_LTLIBOBJS)
1004 EXTRA_DIST += libltdl/test.c
1006 AT_DATA([Makefile.am], [[AM_CPPFLAGS =
1007 include $(top_srcdir)/ltdl.mk
1008 AM_LIBTOOLFLAGS = --quiet
1011 test_LDADD = libltdl/libltdl.la
1012 all-local: ; @printf '%s\n' $(AM_CPPFLAGS)
1014 AT_DATA([libltdl/test.c], [[#include <stdio.h>
1015 int foo(void) { printf("%s\n", STRING); return 0; }
1017 AT_DATA([libltdl/ltdl.c], [[int foo(void); int main(void) { return foo(); }
1020 AT_CHECK([test_fix_ltdl -i ltdl.mk.in -o ltdl.mk])
1021 libtoolize; TEST_AUTORECONF
1022 TEST_CONFIGURE([--disable-shared])
1023 AT_CHECK([make -s && ./test], [0], [
1027 AT_SETUP([fix-ltdl.pl LIBOBJ mangling (<automake-1.16)])
1029 TEST_FIND_AUTOMAKE([default 1.10 1.11 1.12 1.13 1.14 1.15],
1030 [AS_VERSION_COMPARE(["$amver"], [1.16], [], [continue], [continue])])
1031 TEST_LTDL_LIBOBJ_MANGLING
1035 AT_SETUP([fix-ltdl.pl LIBOBJ mangling (>=automake-1.16)])
1037 TEST_FIND_AUTOMAKE([default 1.16 1.17 1.18 1.19],
1038 [AS_VERSION_COMPARE(["$amver"], [1.16], [continue])])
1039 TEST_LTDL_LIBOBJ_MANGLING