]> git.draconx.ca Git - dxcommon.git/blob - tests/scripts.at
9c5f56a950eb4391aa8d3b390117a53c4956bc10
[dxcommon.git] / tests / scripts.at
1 dnl Copyright © 2021-2022 Nick Bowler
2 dnl
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.
6
7 AT_BANNER([Script tests])
8
9 AT_SETUP([gen-options.awk])
10
11 AT_DATA([options.def],
12 [[--option-only
13 --option-with-val (5)
14 --option-with-flagval (&x, 5)
15 --option-with-arg=ARG
16 some "text" goes here
17 --option-with-optional-arg[=OPTIONAL]
18
19 hello
20 -a, --option-with-sopt
21
22 -b, --option-with-sopt-and-arg=SOPTARG
23 -c, --option-with-sopt-and-optional-arg[=SOPTOPTIONAL]
24 --option-with-arg-and-val=ARGVAL (42)
25 --option-with-arg-and-flagval=ARGFLAGVAL (&a[1], 'x')
26 --option-with-optional-arg-and-val[=OPTIONALARGVAL] (54)
27 --option-with-optional-arg-and-flagval[=OPTIONALFLAGVAL] (0, 0)
28 --with-sopt
29 Here is a help string
30     that has a line randomly indented
31 # with a comment
32     @&t@
33 and a blank line
34 --with-arg=ARG
35 do stuff with ARG
36 --flagval
37 ]])
38
39 AT_CHECK([$AWK -f "$builddir/scripts/gen-options.awk" <options.def >options.h])
40
41 AT_DATA([context.h],
42 [[struct option { const char *name; int has_arg; int *flag; int val; };
43 int x, a[5];
44 ]])
45
46 # test 0: sanity test
47 AT_DATA([test0.c],
48 [[#include "context.h"
49 #include "options.h"
50
51 static const char sopts[] = SOPT_STRING;
52 static const struct option opts[] = { LOPTS_INITIALIZER, {0} };
53
54 int main(void)
55 {
56   return 0;
57 }
58 ]])
59 AT_CHECK([$CC -o test0$EXEEXT test0.c && ./test0$EXEEXT], [0], [], [ignore])
60
61 # test 1: long option names and help text
62 AT_DATA([test1.c],
63 [[#include <stdio.h>
64 #include <stdlib.h>
65
66 #include "context.h"
67 #include "options.h"
68
69 static const struct option opts[] = { LOPTS_INITIALIZER };
70
71 int main(void)
72 {
73   unsigned i;
74
75   for (i = 0; i < sizeof opts / sizeof opts[0]; i++) {
76     struct lopt_help help = { "INVALID", "INVALID" };
77
78     if (!lopt_get_help(&opts[i], &help))
79       return EXIT_FAILURE;
80
81     printf("--%s", opts[i].name);
82     if (opts[i].has_arg)
83       printf("=%s", help.arg);
84     printf("\n%s", help.desc);
85     if (help.desc[0])
86       putchar('\n');
87   }
88
89   return 0;
90 }
91 ]])
92
93 # pick out interesting bits from the definitions file
94 sed -n '/^-/s/^.*--\([[^\= @<:@]]*\).*$/\1/p' options.def >options
95 sed -n '/^-/{
96   s/[[^=]]*\(=[[^@:>@ ]]*\).*$/\1/
97   s/^[[^=]].*//
98   s/^=//
99   p
100 }' options.def >argnames
101
102 AS_ECHO(["-"]) | sed -n '1s/^-.*//p
103 1,/^-/d
104 t clear
105 :clear
106 s/^-.*//p
107 t
108 s/^#.*//
109 s/^ *//
110 t next
111 :next
112 N
113 s/\n-.*//
114 t done
115 s/\n#.*//
116 s/\n */\n/g
117 t next
118 :done
119 s/"/\\\\"/g
120 s/[[^\n]][[^\n]]*/\\"&\\"/g
121 s/^\n*//
122 s/\n*$//
123 s/\n\n*/ /g
124 p
125 ' options.def - >helptext
126
127 exec 3<options 4<argnames 5<helptext 6>expout
128 while read opt <&3 && read arg <&4 && read help <&5; do
129   if test ${arg:+y}; then
130     AS_ECHO(["--$opt=$arg"]) >&6
131   else
132     AS_ECHO(["--$opt"]) >&6
133   fi
134   eval "set x $help"; shift
135   for arg
136   do
137     AS_ECHO(["$arg"]) >&6
138   done
139 done
140 exec 3<&- 4<&- 5<&- 6>&-
141
142 AT_CHECK([$CC -o test1$EXEEXT test1.c && ./test1$EXEEXT],
143   [0], [expout], [ignore])
144
145 # test 2: short option string
146 AT_DATA([test2.c],
147 [[#include <stdio.h>
148 #include <stdlib.h>
149
150 #include "context.h"
151 #include "options.h"
152
153 int main(void)
154 {
155   struct option lopts[] = {LOPTS_INITIALIZER};
156   unsigned i, j;
157
158   for (i = 0; i < sizeof SOPT_STRING - 1; i++) {
159     if (SOPT_STRING[i] != ':') {
160       for (j = 0; j < sizeof lopts / sizeof lopts[0]; j++) {
161         if (lopts[j].val == SOPT_STRING[i]) {
162           printf("--%s ", lopts[j].name);
163           break;
164         }
165       }
166     }
167     putchar(SOPT_STRING[i]);
168     if (SOPT_STRING[i+1] != ':')
169       putchar('\n');
170   }
171 }
172 ]])
173
174 sed -n '/^-/{
175   s/=.*/:/
176   s/[[@<:@]]/:/
177   s/^-\([[^-]]\)[[^:]]*/\1/p
178   s/^-.*//p
179 }' options.def >sopts
180
181 exec 3<options 4<sopts 5>expout
182 while read lopt <&3 && read sopt <&4; do
183   if test ${sopt:+y}; then
184     AS_ECHO(["--$lopt $sopt"]) >&5
185   fi
186 done
187 exec 3<&- 4<&- 5>&-
188
189 AT_CHECK([$CC -o test2$EXEEXT test2.c && ./test2$EXEEXT],
190   [0], [expout], [ignore])
191
192 # Check that all help strings are translatable
193 sed 's/\([[^\\]]\\\)" /\1\\n\\" /g' helptext >help-po
194 exec 3<options 4<argnames 5<help-po 6>expected.po
195 while read opt <&3 && read arg <&4 && read help <&5; do
196   if test ${arg:+y}; then
197     AS_ECHO(["msgctxt \"$opt\" msgid \"$arg\""]) >&6
198   fi
199   AS_ECHO(["msgctxt \"$opt\" msgid${help:+ }$help"]) >&6
200 done
201 exec 3<&- 4<&- 5<&- 6>&-
202
203 AT_CHECK([xgettext --keyword=PN_:1c,2 options.h
204   test -f messages.po || exit 77])
205
206 LC_ALL=C sort expected.po >expout
207 AT_CHECK([sed -n '/^msgctxt/{
208 t next
209 :next
210 N
211 s/\nmsgstr.*//
212 t done
213 s/\s*""//
214 s/\n/ /
215 t next
216 :done
217 p
218 }' messages.po | LC_ALL=C sort], [0], [expout])
219
220 AT_CLEANUP
221
222 AT_SETUP([gen-strtab.awk])
223
224 AT_DATA([test.def],
225 [[
226 &a world
227 &b
228 hello world
229 &c
230 hello
231 world
232 &d world\n
233 &e
234 \\not a newline
235 &f
236 \not a newline
237 &g inline
238 continued
239 &h    no\
240 newline\
241 &i
242 \   leading whitespace
243 &j oneline
244 # with a comment
245 ]])
246
247 AT_CHECK([$AWK -f "$builddir/scripts/gen-strtab.awk" <test.def >test.h])
248
249 sed -n 's/^[[&]]\([[^ ]]*\).*/\1/p' test.def >identifiers
250
251 # test 0: sanity test
252 AT_DATA([test0.c],
253 [[#include "test.h"
254 #include <stdio.h>
255
256 int main(void)
257 {
258   printf("---\n");
259 ]])
260 exec 3<identifiers 4>>test0.c
261 while read ident <&3; do
262   AS_ECHO(['  printf("%s\n---\n", '"strtab+$ident);"]) >&4
263 done
264 AS_ECHO(['  return 0;']) >&4
265 AS_ECHO(['}']) >&4
266 exec 3<&- 4>&-
267
268 AT_CHECK([$CC -o test0$EXEEXT test0.c && ./test0$EXEEXT], [0], [---
269 world
270 ---
271 hello world
272
273 ---
274 hello
275 world
276
277 ---
278 world
279
280 ---
281 \not a newline
282
283 ---
284
285 ot a newline
286
287 ---
288 inline
289 continued
290
291 ---
292 nonewline
293 ---
294    leading whitespace
295
296 ---
297 oneline
298 ---
299 ], [ignore])
300
301 AT_CLEANUP
302
303 AT_SETUP([gen-tree.awk])
304 AT_DATA([tree.def],
305 [[ROOT0
306   r0a, r0a_OFFSET
307     r0b, r0b_OFFSET
308       r0c
309     r0d
310   r0e, r0e_OFFSET
311     r0f
312     r0g
313 ROOT1
314   r1a, r1a_OFFSET
315     r1b, r1b_OFFSET
316       r1b
317       r1e
318       r1b
319   r1c, r1c_OFFSET
320     r1d, r1d_OFFSET
321       r1e
322       r1b
323       r1e
324 ]])
325
326 AT_CHECK([$AWK -f "$builddir/scripts/gen-tree.awk" <tree.def >tree.h])
327
328 AT_DATA([test0.c],
329 [[#include "tree.h"
330 #include <stdio.h>
331
332 struct tree { unsigned id, subtree; };
333
334 static const struct tree tree0[] = {
335   ROOT0_INITIALIZER
336 };
337 static const struct tree tree1[] = {
338   ROOT1_INITIALIZER
339 };
340
341 void print_subtree(const struct tree *root, unsigned offset, int depth)
342 {
343   const struct tree *node;
344
345   for (node = &root[offset]; node->id; node++) {
346     printf("%*s%s", 2*depth, "", &tree_strtab[node->id]);
347     if (node->subtree) {
348       printf(", %s_OFFSET\n", &tree_strtab[node->id]);
349       print_subtree(root, node->subtree, depth+1);
350     } else {
351       putchar('\n');
352     }
353   }
354 }
355
356 int main(void)
357 {
358   printf("ROOT0\n");
359   print_subtree(tree0, 0, 1);
360   printf("ROOT1\n");
361   print_subtree(tree1, 0, 1);
362 }
363 ]])
364 cp tree.def expout
365 AT_CHECK([$CC -o test0$EXEEXT test0.c && ./test0$EXEEXT], [0], [expout])
366
367 AT_CLEANUP
368
369 AT_SETUP([join.awk])
370
371 JOIN="$AWK -f $builddir/scripts/join.awk --"
372
373 AT_DATA([a],
374 [[1 a
375 3 a1 x
376 3 a2 x
377 5 a
378 6 a
379 8 a1 x
380 8 a2 x
381 9 a1
382 9 a2
383 9 a3
384 ]])
385
386 AT_DATA([b],
387 [[2 b
388 2 b
389 3 b y
390 4 b
391 6 b1 y
392 6 b2 y
393 7 b
394 8 b1 y
395 8 b2 y
396 ]])
397
398 AT_CHECK([$JOIN a b], [0],
399 [[3 a1 x b y
400 3 a2 x b y
401 6 a b1 y
402 6 a b2 y
403 8 a1 x b1 y
404 8 a1 x b2 y
405 8 a2 x b1 y
406 8 a2 x b2 y
407 ]])
408
409 AT_CHECK([$JOIN -v1 a b], [0],
410 [[1 a
411 5 a
412 9 a1
413 9 a2
414 9 a3
415 ]])
416
417 AT_CHECK([$JOIN -v2 a b], [0],
418 [[2 b
419 2 b
420 4 b
421 7 b
422 ]])
423
424 AT_CHECK([$JOIN -v1 -v2 a b], [0],
425 [[1 a
426 2 b
427 2 b
428 4 b
429 5 a
430 7 b
431 9 a1
432 9 a2
433 9 a3
434 ]])
435
436 AT_CHECK([$JOIN -a1 a b], [0],
437 [[1 a
438 3 a1 x b y
439 3 a2 x b y
440 5 a
441 6 a b1 y
442 6 a b2 y
443 8 a1 x b1 y
444 8 a1 x b2 y
445 8 a2 x b1 y
446 8 a2 x b2 y
447 9 a1
448 9 a2
449 9 a3
450 ]])
451
452 AT_CHECK([$JOIN -a2 a b], [0],
453 [[2 b
454 2 b
455 3 a1 x b y
456 3 a2 x b y
457 4 b
458 6 a b1 y
459 6 a b2 y
460 7 b
461 8 a1 x b1 y
462 8 a1 x b2 y
463 8 a2 x b1 y
464 8 a2 x b2 y
465 ]])
466
467 AT_CHECK([$JOIN -a1 -a2 a b], [0],
468 [[1 a
469 2 b
470 2 b
471 3 a1 x b y
472 3 a2 x b y
473 4 b
474 5 a
475 6 a b1 y
476 6 a b2 y
477 7 b
478 8 a1 x b1 y
479 8 a1 x b2 y
480 8 a2 x b1 y
481 8 a2 x b2 y
482 9 a1
483 9 a2
484 9 a3
485 ]])
486
487 AT_CHECK([$JOIN b a], [0],
488 [[3 b y a1 x
489 3 b y a2 x
490 6 b1 y a
491 6 b2 y a
492 8 b1 y a1 x
493 8 b1 y a2 x
494 8 b2 y a1 x
495 8 b2 y a2 x
496 ]])
497
498 AT_CHECK([$JOIN -v1 b a], [0],
499 [[2 b
500 2 b
501 4 b
502 7 b
503 ]])
504
505 AT_CHECK([$JOIN -v2 b a], [0],
506 [[1 a
507 5 a
508 9 a1
509 9 a2
510 9 a3
511 ]])
512
513 AT_CHECK([$JOIN -v1 -v2 b a], [0],
514 [[1 a
515 2 b
516 2 b
517 4 b
518 5 a
519 7 b
520 9 a1
521 9 a2
522 9 a3
523 ]])
524
525 AT_CHECK([$JOIN -a1 b a], [0],
526 [[2 b
527 2 b
528 3 b y a1 x
529 3 b y a2 x
530 4 b
531 6 b1 y a
532 6 b2 y a
533 7 b
534 8 b1 y a1 x
535 8 b1 y a2 x
536 8 b2 y a1 x
537 8 b2 y a2 x
538 ]])
539
540 AT_CHECK([$JOIN -a2 b a], [0],
541 [[1 a
542 3 b y a1 x
543 3 b y a2 x
544 5 a
545 6 b1 y a
546 6 b2 y a
547 8 b1 y a1 x
548 8 b1 y a2 x
549 8 b2 y a1 x
550 8 b2 y a2 x
551 9 a1
552 9 a2
553 9 a3
554 ]])
555
556 AT_CHECK([$JOIN -a1 -a2 b a], [0],
557 [[1 a
558 2 b
559 2 b
560 3 b y a1 x
561 3 b y a2 x
562 4 b
563 5 a
564 6 b1 y a
565 6 b2 y a
566 7 b
567 8 b1 y a1 x
568 8 b1 y a2 x
569 8 b2 y a1 x
570 8 b2 y a2 x
571 9 a1
572 9 a2
573 9 a3
574 ]])
575
576 AT_CHECK([echo wat | $JOIN -v1 - /dev/null], [0],
577 [[wat
578 ]])
579
580 AT_CLEANUP
581
582 m4_divert_push([PREPARE_TESTS])dnl
583 test_fix_ltdl () {
584   $PERL -e 'my $x = 42; exit $x;'; test $? = 42 || exit 77
585   $PERL -f "$srcdir/scripts/fix-ltdl.pl" "$@"
586 }
587 test_fix_gnulib () {
588   $PERL -e 'my $x = 42; exit $x;'; test $? = 42 || exit 77
589   $PERL -f "$srcdir/scripts/fix-gnulib.pl" "$@"
590 }
591 test_gnulib_mk () {
592   echo; sed -n -f - "$srcdir/tests/data/gnulib.mk" <<EOF
593 /^## begin gnulib module $1/,/^## end   gnulib module $1/p
594 EOF
595 }
596 m4_divert_pop([PREPARE_TESTS])
597
598 AT_SETUP([fix-gnulib.pl SED_HEADER variables])
599
600 test_gnulib_mk gen-header >test.mk.in
601 AT_CHECK([grep SED_HEADER test.mk.in >expout || exit 99])
602 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
603 grep SED_HEADER test.mk], [0], [expout])
604
605 AT_CLEANUP
606
607 AT_SETUP([fix-gnulib.pl %reldir% substitution])
608
609 test_gnulib_mk sys_types >test.mk.in
610 AT_CHECK([grep '%reldir%' test.mk.in >/dev/null || exit 99])
611
612 sed -n -f - test.mk.in >expout <<'EOF'
613 ${G;p;b}
614 /^## begin gnulib/,/^## end   gnulib/!b
615 /^#/{p;b}
616 s|(srcdir)|(top_srcdir)|
617 s|%reldir%|lib|
618 s|BUILT_SOURCES|gnulib_core_headers|
619 s|sys[[/_]]|lib/&|g
620 /^MOSTLYCLEANFILES/{h;b}
621 p
622 EOF
623
624 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
625 sed -n -e '/^## begin gnulib/,/^## end   gnulib/p' \
626        -e '/CLEANFILES/p' test.mk],
627 [0], [expout])
628
629 AT_CLEANUP
630
631 AT_SETUP([fix-gnulib.pl warning removal])
632
633 AT_DATA([test.mk.in], [[
634 ## test begin
635 noinst_LTLIBRARIES += libgnu.la
636 libgnu_la_CFLAGS = $(AM_CFLAGS) $(GL_CFLAG_GNULIB_WARNINGS)
637 noinst_LIBRARIES += libgnu.a
638 libgnu_a_CFLAGS = $(AM_CFLAGS) $(GL_CFLAG_GNULIB_WARNINGS)
639 ## test end
640 ]])
641 AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit
642 sed -n '/^## test begin/,/^## test end/p' test.mk], [0], [## test begin
643 EXTRA_LTLIBRARIES += libgnu.la
644 EXTRA_LIBRARIES += libgnu.a
645 ## test end
646 ])
647
648 AT_CLEANUP
649
650 dnl TEST_FIND_AUTOMAKE_VER([to-check], [test-action])
651 dnl
652 dnl For each whitespace-separated version token in to-check, check if we can
653 dnl run the programs automake-VER and aclocal-VER.  The special token 'default'
654 dnl also checks the unversioned automake and aclocal (or, if set in the
655 dnl environment, $AUTOMAKE and $ACLOCAL).
656 dnl
657 dnl Then test-action is expanded such that shell variables $ac and $am refer to
658 dnl the aclocal and automake programs, and $amver is the actual version
659 dnl reported by --version.  The action should do nothing if the version is
660 dnl acceptable, or "continue" if the version is unacceptable.
661 dnl
662 dnl If an acceptable version is found, the AUTOMAKE and ACLOCAL environment
663 dnl variables are set accordingly.  Otherwise, the test group is skipped.
664 m4_define([TEST_FIND_AUTOMAKE],
665 [have_am=false
666 for am in $1; do
667   AS_CASE([$am],
668     [default], [ac=${ACLOCAL-aclocal} am=${AUTOMAKE-automake}],
669     [ac=aclocal-$am; am=automake-$am])
670   amver=`$am --version | sed -n '1s/.* //p'`
671   acver=`$ac --version | sed -n '1s/.* //p'`
672   set x $amver $acver; shift; test x"$[]#" = x"2" || continue
673   test x"$amver" = x"$acver" || continue
674   $2
675   have_am=:; break
676 done
677 AT_CHECK([$have_am || exit 77])
678 AUTOMAKE=$am; export AUTOMAKE
679 ACLOCAL=$ac; export ACLOCAL
680 AT_CHECK([$ACLOCAL --version && $AUTOMAKE --version], [0], [stdout])
681 ])
682
683 m4_define([TEST_LTDL_LIBOBJ_MANGLING],
684 [TEST_CONFIGURE_AC([[AM_INIT_AUTOMAKE([foreign subdir-objects])
685 AC_PROG_CC
686 LT_INIT
687 AC_SUBST([ltdl_LTLIBOBJS], [libltdl/test.lo])
688 AC_CONFIG_FILES([Makefile])
689 ]])
690
691 mkdir libltdl
692 AT_DATA([ltdl.mk.in], [[
693 AM_CPPFLAGS += -DSTRING=\"helloworld\"
694
695 noinst_LTLIBRARIES = libltdl/libltdl.la
696 libltdl_libltdl_la_SOURCES = libltdl/ltdl.c
697 libltdl_libltdl_la_LIBADD = $(ltdl_LTLIBOBJS)
698 libltdl_libltdl_la_DEPENDENCIES = $(ltdl_LTLIBOBJS)
699
700 EXTRA_DIST += libltdl/test.c
701 ]])
702 AT_DATA([Makefile.am], [[AM_CPPFLAGS =
703 include $(top_srcdir)/ltdl.mk
704 AM_LIBTOOLFLAGS = --quiet
705 bin_PROGRAMS = test
706 test_SOURCES =
707 test_LDADD = libltdl/libltdl.la
708 all-local: ; @printf '%s\n' $(AM_CPPFLAGS)
709 ]])
710 AT_DATA([libltdl/test.c], [[#include <stdio.h>
711 int foo(void) { printf("%s\n", STRING); return 0; }
712 ]])
713 AT_DATA([libltdl/ltdl.c], [[int foo(void); int main(void) { return foo(); }
714 ]])
715
716 AT_CHECK([test_fix_ltdl -i ltdl.mk.in -o ltdl.mk])
717 libtoolize; TEST_AUTORECONF
718 TEST_CONFIGURE([--disable-shared])
719 AT_CHECK([make -s && ./test], [0], [
720 helloworld
721 ])])
722
723 AT_SETUP([fix-ltdl.pl LIBOBJ mangling (<automake-1.16)])
724
725 TEST_FIND_AUTOMAKE([default 1.10 1.11 1.12 1.13 1.14 1.15],
726   [AS_VERSION_COMPARE(["$amver"], [1.16], [], [continue], [continue])])
727 TEST_LTDL_LIBOBJ_MANGLING
728
729 AT_CLEANUP
730
731 AT_SETUP([fix-ltdl.pl LIBOBJ mangling (>=automake-1.16)])
732
733 TEST_FIND_AUTOMAKE([default 1.16 1.17 1.18 1.19],
734   [AS_VERSION_COMPARE(["$amver"], [1.16], [continue])])
735 TEST_LTDL_LIBOBJ_MANGLING
736
737 AT_CLEANUP