]> git.draconx.ca Git - dxcommon.git/blobdiff - tests/scripts.at
tests: Ignore output from the C compiler.
[dxcommon.git] / tests / scripts.at
index 4784b5994929953114c4c6c11e4cd7a3c97a95d6..1748070616dd0477226cafc0694a9c678491c3e4 100644 (file)
@@ -1,8 +1,50 @@
+dnl Copyright © 2021-2024 Nick Bowler
+dnl
+dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+dnl This is free software: you are free to do what the fuck you want to.
+dnl There is NO WARRANTY, to the extent permitted by law.
+
 AT_BANNER([Script tests])
 
-AT_SETUP([gen-options.awk])
+AT_SETUP([bake-config.awk])
+AT_KEYWORDS([bake-config awk script scripts])
+
+AT_DATA([cfg.h],
+[[#define hello world
+/* #undef HAVE_STUFF */
+#define HAVE_OTHER_STUFF 1
+/* #undef HAVE_CRAZY_STUFF */
+]])
+
+AT_DATA([lib.h],
+[[#if HAVE_STUFF
+#  define foo hello__
+#elif HAVE_CRAZY_STUFF
+#  define foo hello
+#elif HAVE_OTHER_STUFF
+#  define foo __hello
+#endif
+]])
+
+AT_CHECK([$AWK -f "$srcdir/scripts/bake-config.awk" cfg.h lib.h], [0],
+[[#if 0 /* HAVE_STUFF */
+#  define foo hello__
+#elif 0 /* HAVE_CRAZY_STUFF */
+#  define foo world /* hello */
+#elif 1 /* HAVE_OTHER_STUFF */
+#  define foo __hello
+#endif
+]])
 
-AT_DATA([options.def],
+AT_CLEANUP
+
+m4_define([TEST_GEN_OPTIONS],
+[AT_KEYWORDS([gen-options awk script scripts])dnl
+AT_DATA([m4_default([$2], [options.def])], [$1])
+AT_CHECK([$AWK -f "$srcdir/scripts/gen-options.awk" dnl
+<m4_default([$2], [options.def]) >options.h])])
+
+m4_define([TEST_GEN_OPTIONS_SAMPLE],
 [[--option-only
 --option-with-val (5)
 --option-with-flagval (&x, 5)
@@ -30,7 +72,8 @@ do stuff with ARG
 --flagval
 ]])
 
-AT_CHECK([$AWK -f "$builddir/scripts/gen-options.awk" <options.def >options.h])
+AT_SETUP([gen-options.awk])
+TEST_GEN_OPTIONS([TEST_GEN_OPTIONS_SAMPLE])
 
 AT_DATA([context.h],
 [[struct option { const char *name; int has_arg; int *flag; int val; };
@@ -50,7 +93,8 @@ int main(void)
   return 0;
 }
 ]])
-AT_CHECK([$CC -o test0$EXEEXT test0.c && ./test0$EXEEXT], [0], [], [ignore])
+AT_CHECK([$CC -o test0$EXEEXT test0.c 1>&2 && ./test0$EXEEXT],
+  [0], [], [ignore])
 
 # test 1: long option names and help text
 AT_DATA([test1.c],
@@ -84,56 +128,24 @@ int main(void)
 }
 ]])
 
-# pick out interesting bits from the definitions file
-sed -n '/^-/s/^.*--\([[^\= @<:@]]*\).*$/\1/p' options.def >options
-sed -n '/^-/{
-  s/[[^=]]*\(=[[^@:>@ ]]*\).*$/\1/
-  s/^[[^=]].*//
-  s/^=//
-  p
-}' options.def >argnames
-
-AS_ECHO(["-"]) | sed -n '1s/^-.*//p
-1,/^-/d
-t clear
-:clear
-s/^-.*//p
-t
-s/^#.*//
-s/^ *//
-t next
-:next
-N
-s/\n-.*//
-t done
-s/\n#.*//
-s/\n */\n/g
-t next
-:done
-s/"/\\\\"/g
-s/[[^\n]][[^\n]]*/\\"&\\"/g
-s/^\n*//
-s/\n*$//
-s/\n\n*/ /g
-p
-' options.def - >helptext
-
-exec 3<options 4<argnames 5<helptext 6>expout
-while read opt <&3 && read arg <&4 && read help <&5; do
-  if test ${arg:+y}; then
-    AS_ECHO(["--$opt=$arg"]) >&6
-  else
-    AS_ECHO(["--$opt"]) >&6
-  fi
-  eval "set x $help"; shift
-  for arg
-  do
-    AS_ECHO(["$arg"]) >&6
-  done
-done
-exec 3<&- 4<&- 5<&- 6>&-
+AT_DATA([lopthelp.awk],
+[[/^#/ { next }
+/^-/ {
+  if ($1 !~ /^--/)
+    $1 = $2;
+  if (sub(/\@:>@$/, "", $1))
+    sub(/\@<:@/, "", $1);
+
+  print $1;
+  next;
+}
+
+{ sub(/^[ \t]*/, ""); }
+/./ { print; }
+]])
 
-AT_CHECK([$CC -o test1$EXEEXT test1.c && ./test1$EXEEXT],
+$AWK -f lopthelp.awk options.def >expout
+AT_CHECK([$CC -o test1$EXEEXT test1.c 1>&2 && ./test1$EXEEXT],
   [0], [expout], [ignore])
 
 # test 2: short option string
@@ -162,42 +174,88 @@ int main(void)
     if (SOPT_STRING[i+1] != ':')
       putchar('\n');
   }
+  return 0;
 }
 ]])
 
-sed -n '/^-/{
-  s/=.*/:/
-  s/[[@<:@]]/:/
-  s/^-\([[^-]]\)[[^:]]*/\1/p
-  s/^-.*//p
-}' options.def >sopts
+AT_DATA([soptstr.awk],
+[[/^-/ {
+  if ($1 ~ /^--/)
+    next;
 
-exec 3<options 4<sopts 5>expout
-while read lopt <&3 && read sopt <&4; do
-  if test ${sopt:+y}; then
-    AS_ECHO(["--$lopt $sopt"]) >&5
-  fi
-done
-exec 3<&- 4<&- 5>&-
+  sopt = substr($1, 2, 1);
+  arg = sub(/\@:>@$/, "", $2);
+  arg += sub(/\@<:@?=.*$/, "", $2);
+
+  print $2 " " sopt substr("::", 1, arg);
+}
+]])
 
-AT_CHECK([$CC -o test2$EXEEXT test2.c && ./test2$EXEEXT],
+$AWK -f soptstr.awk options.def >expout
+AT_CHECK([$CC -o test2$EXEEXT test2.c 1>&2 && ./test2$EXEEXT],
   [0], [expout], [ignore])
 
+AT_CLEANUP
+
+AT_SETUP([gen-options.awk xgettext annotation])
+TEST_GEN_OPTIONS([TEST_GEN_OPTIONS_SAMPLE])
+
 # Check that all help strings are translatable
-sed 's/\([[^\\]]\\\)" /\1\\n\\" /g' helptext >help-po
-exec 3<options 4<argnames 5<help-po 6>expected.po
-while read opt <&3 && read arg <&4 && read help <&5; do
-  if test ${arg:+y}; then
-    AS_ECHO(["msgctxt \"$opt\" msgid \"$arg\""]) >&6
-  fi
-  AS_ECHO(["msgctxt \"$opt\" msgid${help:+ }$help"]) >&6
-done
-exec 3<&- 4<&- 5<&- 6>&-
+AT_DATA([messages.awk],
+[[BEGIN { lines = -1; }
+END { output(); }
+
+/^#/ { next }
+/^-/ {
+  output();
+  if ($1 !~ /^--/)
+    $1 = $2;
+
+  tmp=$1;
+  arg="";
+  if (sub(/\@<:@?=.*/, "", $1)) {
+    arg = substr(tmp, index(tmp, "=")+1);
+    sub(/\@:>@$/, "", arg);
+  }
+
+  sub(/^--/, "", $1);
+  ctxt=("msgctxt \"" $1 "\" msgid");
+
+  if (arg)
+    print ctxt, ("\"" arg "\"");
+  next;
+}
+
+{ sub(/^[ \t]*/, ""); }
+/./ {
+  gsub(/"/, "\\\"", $0);
+  help[lines++] = $0;
+}
+
+function output(i)
+{
+  if (lines >= 0) {
+    printf "%s", ctxt;
+    for (i = 0; i < lines; i++) {
+      nl = (i+1 < lines ? "\\n" : "");
+      printf(" \"%s%s\"", help[i], nl);
+    }
+    print "";
+  }
 
+  lines = 0;
+}
+]])
+
+dnl Antique versions of xgettext which predate the pgettext/msgctx feature
+dnl will produce an output po file with no msgctx lines.  So try to spot
+dnl that and skip the test with such versions.
 AT_CHECK([xgettext --keyword=PN_:1c,2 options.h
-  test -f messages.po || exit 77])
+  test -f messages.po || exit 77
+  grep msgid messages.po >/dev/null &&
+    { grep msgctx messages.po >/dev/null || exit 77; }])
 
-LC_ALL=C sort expected.po >expout
+$AWK -f messages.awk options.def | LC_ALL=C sort >expout
 AT_CHECK([sed -n '/^msgctxt/{
 t next
 :next
@@ -213,7 +271,70 @@ p
 
 AT_CLEANUP
 
+AT_SETUP([gen-options.awk packed format])
+
+AT_DATA([test.c], [[#include <stdio.h>
+struct option { const char *name; int has_arg; int *flag; int val; };
+
+#include "options.h"
+
+static unsigned opts[] = { LOPTS_PACKED_INITIALIZER };
+
+int main(void)
+{
+  unsigned i;
+  int x =
+#if !LOPT_PACK_BITS
+  0
+#elif LOPT_PACK_BITS <= 8
+  1
+#elif LOPT_PACK_BITS <= 16
+  2
+#elif LOPT_PACK_BITS <= 32
+  3
+#else
+#  error too big
+#endif
+  ;
+  printf("%d\n", x);
+  for (i = 0; i < sizeof opts / sizeof opts[0]; i++) {
+    struct option o;
+
+    LOPT_UNPACK(o, opts[i]);
+    printf("--%s, %d, ", o.name, o.has_arg);
+    if (o.val > UCHAR_MAX)
+      printf("%d\n", o.val - UCHAR_MAX - 1);
+    else
+      printf("'%c'\n", o.val);
+  }
+  return 0;
+}
+]])
+
+TEST_GEN_OPTIONS([[--single-option
+]], [single.dat])
+AT_CHECK([$CC -o single$EXEEXT test.c 1>&2 && ./single$EXEEXT], [0],
+[[0
+--single-option, 0, 0
+]], [ignore])
+
+TEST_GEN_OPTIONS([[-a, --the-first-option
+-b, --the-second-option=ARG
+-c, --the-third-option[=ARG]
+-d, --the-fourth-option
+]], [16bit.dat])
+AT_CHECK([$CC -o 16bit$EXEEXT test.c 1>&2 && ./16bit$EXEEXT], [0],
+[[2
+--the-first-option, 0, 'a'
+--the-second-option, 1, 'b'
+--the-third-option, 2, 'c'
+--the-fourth-option, 0, 'd'
+]], [ignore])
+
+AT_CLEANUP
+
 AT_SETUP([gen-strtab.awk])
+AT_KEYWORDS([gen-strtab awk script scripts])
 
 AT_DATA([test.def],
 [[
@@ -236,30 +357,28 @@ newline\
 \   leading whitespace
 &j oneline
 # with a comment
+&k    with   nontrivial   whitespace
 ]])
 
-AT_CHECK([$AWK -f "$builddir/scripts/gen-strtab.awk" <test.def >test.h])
+AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test.def >test.h])
 
 sed -n 's/^[[&]]\([[^ ]]*\).*/\1/p' test.def >identifiers
 
 # test 0: sanity test
-AT_DATA([test0.c],
-[[#include "test.h"
+{ cat <<'EOF'
+#include "test.h"
 #include <stdio.h>
 
 int main(void)
 {
   printf("---\n");
-]])
-exec 3<identifiers 4>>test0.c
-while read ident <&3; do
-  AS_ECHO(['  printf("%s\n---\n", '"strtab+$ident);"]) >&4
-done
-AS_ECHO(['  return 0;']) >&4
-AS_ECHO(['}']) >&4
-exec 3<&- 4>&-
+EOF
+while read id; do AS_ECHO(['  printf("%s\n---\n", strtab+'"$id"');']); done
+AS_ECHO(['  return 0;'])
+AS_ECHO(['}'])
+} <identifiers >test0.c
 
-AT_CHECK([$CC -o test0$EXEEXT test0.c && ./test0$EXEEXT], [0], [---
+AT_CHECK([$CC -o test0$EXEEXT test0.c 1>&2 && ./test0$EXEEXT], [0], [---
 world
 ---
 hello world
@@ -290,6 +409,648 @@ nonewline
 ---
 oneline
 ---
+with   nontrivial   whitespace
+---
 ], [ignore])
 
 AT_CLEANUP
+
+AT_SETUP([gen-strtab.awk @nozero option])
+AT_KEYWORDS([gen-strtab awk script scripts])
+
+AT_DATA([test0.def],
+[[&hello hello
+]])
+AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test0.def >test0.h])
+
+AT_DATA([test1.def],
+[[@nozero
+&hello hello
+]])
+AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test1.def >test1.h])
+
+AT_DATA([test.c],
+[[#include <stdio.h>
+#include HEADER
+int main(void) { printf("%d %s\n", hello, strtab+hello); return 0; }
+]])
+AT_CHECK([$CC -DHEADER='"test0.h"' -o test0$EXEEXT test.c 1>&2 &&
+  ./test0$EXEEXT], [0], [[0 hello
+]], [ignore])
+AT_CHECK([$CC -DHEADER='"test1.h"' -o test1$EXEEXT test.c 1>&2 &&
+  ./test1$EXEEXT], [0], [[1 hello
+]], [ignore])
+
+AT_CLEANUP
+
+AT_SETUP([gen-strtab.awk @macro option])
+AT_KEYWORDS([gen-strtab awk script scripts])
+
+AT_DATA([test0.def],
+[[@macro
+&foo foobar
+&bar bar
+&baz baz
+]])
+AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test0.def >test0.h])
+
+AT_DATA([test0.c],
+[[#include <stdio.h>
+extern const char strtab[];
+#include "test0.h"
+
+int main(void)
+{
+  static const char mystrtab[] = STRTAB_INITIALIZER;
+  printf("%s\n%s\n%s\n", mystrtab+foo, mystrtab+bar, mystrtab+baz);
+  return 0;
+}
+]])
+AT_CHECK([$CC -o test0$EXEEXT test0.c 1>&2 && ./test0$EXEEXT], [0],
+[[foobar
+bar
+baz
+]], [ignore])
+
+AT_CLEANUP
+
+AT_SETUP([gen-strtab.awk l10n options])
+AT_KEYWORDS([gen-strtab awk script scripts])
+
+AT_DATA([l10n.sed], dnl (
+[[/^#/b
+s/.*N_(\([^)]*\)).*/\1/p
+]])
+
+AT_DATA([test0.def],
+[[&a hello world
+&b world
+&c goodbye
+]])
+AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test0.def >test0.h])
+AT_CHECK([sed -n -f l10n.sed test0.h | LC_ALL=C sort], [0],
+[["goodbye"
+"hello world"
+"world"
+]])
+
+AT_DATA([test1.def],
+[[&a hello world
+&&b world
+&&c goodbye
+]])
+AT_CHECK([$AWK -f "$srcdir/scripts/gen-strtab.awk" <test1.def >test1.h])
+AT_CHECK([sed -n -f l10n.sed test1.h], [0],
+[["hello world"
+]])
+
+AT_DATA([test.c],
+[[#include <stdio.h>
+#include HEADER
+
+int main(void)
+{
+  printf("%s %s %s\n", strtab+a, strtab+b, strtab+c);
+  return 0;
+}
+]])
+
+AT_CHECK([$CC -DHEADER='"test0.h"' -o test0$EXEEXT test.c 1>&2 &&
+  ./test0$EXEEXT], [0], [[hello world world goodbye
+]], [ignore])
+
+AT_CHECK([$CC -DHEADER='"test1.h"' -o test1$EXEEXT test.c 1>&2 &&
+  ./test1$EXEEXT], [0], [[hello world world goodbye
+]], [ignore])
+
+
+AT_CLEANUP
+
+AT_SETUP([gen-tree.awk])
+AT_KEYWORDS([gen-tree awk script scripts])
+
+AT_DATA([tree.def],
+[[# comment
+ROOT0
+  r0a, r0a_OFFSET
+    r0b, r0b_OFFSET
+      r0c
+    r0d
+  r0e, r0e_OFFSET
+    r0f
+    r0g
+# comment
+ROOT1
+  r1a, r1a_OFFSET
+    r1b, r1b_OFFSET
+      r1b
+      r1e
+      r1b
+  r1c, r1c_OFFSET
+    r1d, r1d_OFFSET
+      r1e
+      r1b
+      r1e
+# comment
+]])
+
+AT_CHECK([$AWK -f "$srcdir/scripts/gen-tree.awk" <tree.def >tree.h])
+
+AT_DATA([test0.c],
+[[#include "tree.h"
+#include <stdio.h>
+
+struct tree { unsigned id, subtree; };
+
+static const struct tree tree0[] = {
+  ROOT0_INITIALIZER
+};
+static const struct tree tree1[] = {
+  ROOT1_INITIALIZER
+};
+
+void print_subtree(const struct tree *root, unsigned offset, int depth)
+{
+  const struct tree *node;
+
+  for (node = &root[offset]; node->id; node++) {
+    printf("%*s%s", 2*depth, "", &tree_strtab[node->id]);
+    if (node->subtree) {
+      printf(", %s_OFFSET\n", &tree_strtab[node->id]);
+      print_subtree(root, node->subtree, depth+1);
+    } else {
+      putchar('\n');
+    }
+  }
+}
+
+int main(void)
+{
+  printf("ROOT0\n");
+  print_subtree(tree0, 0, 1);
+  printf("ROOT1\n");
+  print_subtree(tree1, 0, 1);
+  return 0;
+}
+]])
+sed '/^#/d' tree.def >expout
+AT_CHECK([$CC -o test0$EXEEXT test0.c 1>&2 && ./test0$EXEEXT],
+  [0], [expout], [ignore])
+
+AT_CLEANUP
+
+# Test the gen-tree features that avoid creating string labels for nodes.
+AT_SETUP([gen-tree.awk @nostrtab option])
+AT_KEYWORDS([gen-tree awk script scripts])
+
+AT_DATA([tree.def],
+[[@nostrtab
+ROOT
+ a 1, a_OFFSET
+  b 1
+  c 2
+ d 2, d_OFFSET
+  e 1
+  f 2
+]])
+AT_CHECK([$AWK -f "$srcdir/scripts/gen-tree.awk" <tree.def >tree.h])
+
+AT_DATA([test0.c],
+[[float tree_strtab = 0;
+#define a []
+#define b []
+#define c []
+#define e []
+#define f []
+#include "tree.h"
+#include <stdio.h>
+
+static struct { int num, offset; } root[] = { ROOT_INITIALIZER };
+
+int main(void)
+{
+  unsigned i;
+  for (i = 0; i < sizeof root / sizeof root[0]; i++) {
+    printf("%d, %d\n", root[i].num, root[i].offset);
+  }
+  return 0;
+}
+]])
+
+AT_CHECK([$CC -o test0$EXEEXT test0.c 1>&2 && ./test0$EXEEXT], [0],
+[[1, 3
+2, 6
+0, 0
+1, 0
+2, 0
+0, 0
+1, 0
+2, 0
+0, 0
+]], [ignore])
+
+AT_DATA([flat.def],
+[[FLAT
+ a 1
+ b 2
+ c 3
+@nostrtab
+]])
+AT_CHECK([$AWK -f "$srcdir/scripts/gen-tree.awk" <flat.def >flat.h])
+
+sed -e 's/tree\.h/flat.h/' -e 's/ROOT/FLAT/' test0.c >test1.c
+AT_CHECK([$CC -o test1$EXEEXT test1.c 1>&2 && ./test1$EXEEXT], [0],
+[[1, 0
+2, 0
+3, 0
+0, 0
+]], [ignore])
+
+AT_CLEANUP
+
+AT_SETUP([join.awk])
+AT_KEYWORDS([join awk script scripts])
+
+JOIN="$AWK -f $srcdir/scripts/join.awk --"
+
+AT_DATA([a],
+[[1 a
+3 a1 x
+3 a2 x
+5 a
+6 a
+8 a1 x
+8 a2 x
+9 a1
+9 a2
+9 a3
+]])
+
+AT_DATA([b],
+[[2 b
+2 b
+3 b y
+4 b
+6 b1 y
+6 b2 y
+7 b
+8 b1 y
+8 b2 y
+]])
+
+AT_CHECK([$JOIN a b], [0],
+[[3 a1 x b y
+3 a2 x b y
+6 a b1 y
+6 a b2 y
+8 a1 x b1 y
+8 a1 x b2 y
+8 a2 x b1 y
+8 a2 x b2 y
+]])
+
+AT_CHECK([$JOIN -v1 a b], [0],
+[[1 a
+5 a
+9 a1
+9 a2
+9 a3
+]])
+
+AT_CHECK([$JOIN -v2 a b], [0],
+[[2 b
+2 b
+4 b
+7 b
+]])
+
+AT_CHECK([$JOIN -v1 -v2 a b], [0],
+[[1 a
+2 b
+2 b
+4 b
+5 a
+7 b
+9 a1
+9 a2
+9 a3
+]])
+
+AT_CHECK([$JOIN -a1 a b], [0],
+[[1 a
+3 a1 x b y
+3 a2 x b y
+5 a
+6 a b1 y
+6 a b2 y
+8 a1 x b1 y
+8 a1 x b2 y
+8 a2 x b1 y
+8 a2 x b2 y
+9 a1
+9 a2
+9 a3
+]])
+
+AT_CHECK([$JOIN -a2 a b], [0],
+[[2 b
+2 b
+3 a1 x b y
+3 a2 x b y
+4 b
+6 a b1 y
+6 a b2 y
+7 b
+8 a1 x b1 y
+8 a1 x b2 y
+8 a2 x b1 y
+8 a2 x b2 y
+]])
+
+AT_CHECK([$JOIN -a1 -a2 a b], [0],
+[[1 a
+2 b
+2 b
+3 a1 x b y
+3 a2 x b y
+4 b
+5 a
+6 a b1 y
+6 a b2 y
+7 b
+8 a1 x b1 y
+8 a1 x b2 y
+8 a2 x b1 y
+8 a2 x b2 y
+9 a1
+9 a2
+9 a3
+]])
+
+AT_CHECK([$JOIN b a], [0],
+[[3 b y a1 x
+3 b y a2 x
+6 b1 y a
+6 b2 y a
+8 b1 y a1 x
+8 b1 y a2 x
+8 b2 y a1 x
+8 b2 y a2 x
+]])
+
+AT_CHECK([$JOIN -v1 b a], [0],
+[[2 b
+2 b
+4 b
+7 b
+]])
+
+AT_CHECK([$JOIN -v2 b a], [0],
+[[1 a
+5 a
+9 a1
+9 a2
+9 a3
+]])
+
+AT_CHECK([$JOIN -v1 -v2 b a], [0],
+[[1 a
+2 b
+2 b
+4 b
+5 a
+7 b
+9 a1
+9 a2
+9 a3
+]])
+
+AT_CHECK([$JOIN -a1 b a], [0],
+[[2 b
+2 b
+3 b y a1 x
+3 b y a2 x
+4 b
+6 b1 y a
+6 b2 y a
+7 b
+8 b1 y a1 x
+8 b1 y a2 x
+8 b2 y a1 x
+8 b2 y a2 x
+]])
+
+AT_CHECK([$JOIN -a2 b a], [0],
+[[1 a
+3 b y a1 x
+3 b y a2 x
+5 a
+6 b1 y a
+6 b2 y a
+8 b1 y a1 x
+8 b1 y a2 x
+8 b2 y a1 x
+8 b2 y a2 x
+9 a1
+9 a2
+9 a3
+]])
+
+AT_CHECK([$JOIN -a1 -a2 b a], [0],
+[[1 a
+2 b
+2 b
+3 b y a1 x
+3 b y a2 x
+4 b
+5 a
+6 b1 y a
+6 b2 y a
+7 b
+8 b1 y a1 x
+8 b1 y a2 x
+8 b2 y a1 x
+8 b2 y a2 x
+9 a1
+9 a2
+9 a3
+]])
+
+AT_CHECK([echo wat | $JOIN -v1 - /dev/null], [0],
+[[wat
+]])
+
+AT_CLEANUP
+
+m4_divert_push([PREPARE_TESTS])dnl
+test_fix_ltdl () {
+  $PERL -e 'my $x = 42; exit $x;'; test $? = 42 || exit 77
+  $PERL "$srcdir/scripts/fix-ltdl.pl" "$@"
+}
+test_fix_gnulib () {
+  $PERL -e 'my $x = 42; exit $x;'; test $? = 42 || exit 77
+  $PERL "$srcdir/scripts/fix-gnulib.pl" "$@"
+}
+test_gnulib_mk () {
+  echo;
+  for arg
+  do
+    sed -n -e \
+      "/^## begin gnulib module $arg/,/^## end   gnulib module $arg/p" \
+      "$srcdir/tests/data/gnulib.mk"
+  done
+}
+m4_divert_pop([PREPARE_TESTS])
+
+AT_SETUP([fix-gnulib.pl SED_HEADER variables])
+AT_KEYWORDS([fix-gnulib perl script scripts])
+
+test_gnulib_mk gen-header >test.mk.in
+AT_CHECK([grep SED_HEADER test.mk.in >expout || exit 99])
+AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
+grep SED_HEADER test.mk], [0], [expout])
+
+AT_CLEANUP
+
+AT_SETUP([fix-gnulib.pl warning removal])
+AT_KEYWORDS([fix-gnulib perl script scripts])
+
+AT_DATA([test.mk.in], [[
+## test begin
+noinst_LTLIBRARIES += libgnu.la
+libgnu_la_CFLAGS = $(AM_CFLAGS) $(GL_CFLAG_GNULIB_WARNINGS)
+noinst_LIBRARIES += libgnu.a
+libgnu_a_CFLAGS = $(AM_CFLAGS) $(GL_CFLAG_GNULIB_WARNINGS)
+## test end
+]])
+AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
+sed -n '/^## test begin/,/^## test end/p' test.mk], [0], [## test begin
+EXTRA_LTLIBRARIES += libgnu.la
+EXTRA_LIBRARIES += libgnu.a
+## test end
+])
+
+AT_CLEANUP
+
+AT_SETUP([fix-gnulib.pl header directory creation])
+AT_KEYWORDS([fix-gnulib perl script scripts])
+
+AT_DATA([extract.awk],
+[[$0 !~ /^\t/ && $1 ~ /:$/ {
+  target=$1;
+
+  for (i = 2; i <= NF; i++) {
+    if ($i ~ /am__dirstamp/)
+      target = target " " $i;
+  }
+
+  next;
+}
+
+target != "" && sub(/[$][({](AM_V_GEN|gl_V_at)[})].*$/, "[OK]") {
+  print target, $1;
+}
+
+{ target=""; }
+]])
+
+test_gnulib_mk alloca-opt sys_types stddef >test.mk.in
+AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
+$AWK -f extract.awk test.mk], [0],
+[[lib/alloca.h: lib/$(am__dirstamp) [OK]
+lib/sys/types.h: lib/sys/$(am__dirstamp) [OK]
+lib/stddef.h: lib/$(am__dirstamp) [OK]
+]])
+
+AT_CLEANUP
+
+dnl TEST_FIND_AUTOMAKE_VER([to-check], [test-action])
+dnl
+dnl For each whitespace-separated version token in to-check, check if we can
+dnl run the programs automake-VER and aclocal-VER.  The special token 'default'
+dnl also checks the unversioned automake and aclocal (or, if set in the
+dnl environment, $AUTOMAKE and $ACLOCAL).
+dnl
+dnl Then test-action is expanded such that shell variables $ac and $am refer to
+dnl the aclocal and automake programs, and $amver is the actual version
+dnl reported by --version.  The action should do nothing if the version is
+dnl acceptable, or "continue" if the version is unacceptable.
+dnl
+dnl If an acceptable version is found, the AUTOMAKE and ACLOCAL environment
+dnl variables are set accordingly.  Otherwise, the test group is skipped.
+m4_define([TEST_FIND_AUTOMAKE],
+[have_am=false
+for am in $1; do
+  AS_CASE([$am],
+    [default], [ac=${ACLOCAL-aclocal} am=${AUTOMAKE-automake}],
+    [ac=aclocal-$am; am=automake-$am])
+  amver=`$am --version | sed -n '1s/.* //p'`
+  acver=`$ac --version | sed -n '1s/.* //p'`
+  set x $amver $acver; shift; test x"$[]#" = x"2" || continue
+  test x"$amver" = x"$acver" || continue
+  $2
+  have_am=:; break
+done
+AT_CHECK([$have_am || exit 77])
+AUTOMAKE=$am; export AUTOMAKE
+ACLOCAL=$ac; export ACLOCAL
+AT_CHECK([$ACLOCAL --version && $AUTOMAKE --version], [0], [stdout])
+])
+
+m4_define([TEST_LTDL_LIBOBJ_MANGLING],
+[TEST_CONFIGURE_AC([[AM_INIT_AUTOMAKE([foreign subdir-objects])
+AC_PROG_CC
+LT_INIT
+AC_SUBST([ltdl_LTLIBOBJS], [libltdl/test.lo])
+AC_CONFIG_FILES([Makefile])
+]])
+
+mkdir libltdl
+AT_DATA([ltdl.mk.in], [[
+AM_CPPFLAGS += -DSTRING=\"helloworld\"
+
+noinst_LTLIBRARIES = libltdl/libltdl.la
+libltdl_libltdl_la_SOURCES = libltdl/ltdl.c
+libltdl_libltdl_la_LIBADD = $(ltdl_LTLIBOBJS)
+libltdl_libltdl_la_DEPENDENCIES = $(ltdl_LTLIBOBJS)
+
+EXTRA_DIST += libltdl/test.c
+]])
+AT_DATA([Makefile.am], [[AM_CPPFLAGS =
+include $(top_srcdir)/ltdl.mk
+AM_LIBTOOLFLAGS = --quiet
+bin_PROGRAMS = test
+test_SOURCES =
+test_LDADD = libltdl/libltdl.la
+all-local: ; @printf '%s\n' $(AM_CPPFLAGS)
+]])
+AT_DATA([libltdl/test.c], [[#include <stdio.h>
+int foo(void) { printf("%s\n", STRING); return 0; }
+]])
+AT_DATA([libltdl/ltdl.c], [[int foo(void); int main(void) { return foo(); }
+]])
+
+AT_CHECK([test_fix_ltdl -i ltdl.mk.in -o ltdl.mk])
+libtoolize; TEST_AUTORECONF
+TEST_CONFIGURE([--disable-shared])
+AT_CHECK([make -s && ./test], [0], [
+helloworld
+])])
+
+AT_SETUP([fix-ltdl.pl LIBOBJ mangling (<automake-1.16)])
+AT_KEYWORDS([fix-ltdl perl script scripts])
+
+TEST_FIND_AUTOMAKE([default 1.10 1.11 1.12 1.13 1.14 1.15],
+  [AS_VERSION_COMPARE(["$amver"], [1.16], [], [continue], [continue])])
+TEST_LTDL_LIBOBJ_MANGLING
+
+AT_CLEANUP
+
+AT_SETUP([fix-ltdl.pl LIBOBJ mangling (>=automake-1.16)])
+AT_KEYWORDS([fix-ltdl perl script scripts])
+
+TEST_FIND_AUTOMAKE([default 1.16 1.17 1.18 1.19],
+  [AS_VERSION_COMPARE(["$amver"], [1.16], [continue])])
+TEST_LTDL_LIBOBJ_MANGLING
+
+AT_CLEANUP