Stress test for hash resizing.
[m4.git] / tests / others.at
blobf95d80f604ddfca3b2a95f447e412f10f720ed70
1 # Hand crafted tests for GNU M4.                               -*- Autotest -*-
2 # Copyright (C) 2001, 2006, 2007, 2008, 2009 Free Software Foundation,
3 # Inc.
5 # This file is part of GNU M4.
7 # GNU M4 is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
12 # GNU M4 is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 AT_BANNER([Composite macros and other tests.])
23 ## ---------- ##
24 ## capitalize ##
25 ## ---------- ##
27 AT_TEST_M4([Capitalize],
28 [[dnl
29 dnl convert to upper- resp. lowercase
30 define(`upcase', `translit(`$*', `a-z', `A-Z')')
31 define(`downcase', `translit(`$*', `A-Z', `a-z')')
32 upcase(`Convert to upper case')
33 downcase(`Convert To LOWER Case')
34 dnl
35 dnl capitalize a single word
36 define(`capitalize1', `regexp(`$1', `^\(\w\)\(\w*\)', `upcase(`\1')`'downcase(`\2')')')
37 define(`capitalize', `patsubst(`$1', `\w+', ``'capitalize1(`\&')')')
38 capitalize(`This sentence should be capitalized')
39 ]],
42 CONVERT TO UPPER CASE
43 convert to lower case
46 This Sentence Should Be Capitalized
47 ]])
51 ## -------- ##
52 ## comments ##
53 ## -------- ##
55 AT_SETUP([Comments])
57 AT_DATA([input.m4],
58 [[# An ordinary comment
59 define(`foo', # A comment in a macro
60 `Macro `foo' expansion')
61 foo
62 define(`comment', `*** Macro `comment' expansion ***')
63 changecom(`@', `@')
64 foo
65 ]])
67 AT_CHECK_M4([input.m4], [0],
68 [[# An ordinary comment
70 # A comment in a macro
71 Macro foo expansion
74 # A *** Macro comment expansion *** in a macro
75 Macro foo expansion
76 ]])
78 dnl Detect regression in 1.4.10b in regards to reparsing comments.
79 AT_DATA([input.m4],
80 [[define(`e', `$@')define(`q', ``$@'')define(`foo', `bar')
81 q(e(`one
82 ',#two ' foo
84 changecom(`<', `>')define(`n', `$#')
85 n(e(<`>, <'>))
86 len(e(<`>, ,<'>))
87 ]])
89 AT_CHECK_M4([input.m4], [0],
91 `one
92 ',`#two  bar
97 ]])
99 AT_CLEANUP
101 ## --------- ##
102 ## countdown ##
103 ## --------- ##
105 AT_SETUP([countdown])
107 AT_DATA([[exp.m4]],
108 [[define(`countdown', `$1
109 ifelse(eval($1 > 0), 1, `countdown(decr($1))', `Done')')dnl
110 countdown(7)
113 AT_CHECK_M4([exp.m4], 0,
122 Done
125 AT_CLEANUP
128 ## --------- ##
129 ## directory ##
130 ## --------- ##
132 AT_SETUP([directory])
134 AT_DATA([in1.m4],
135 [[include(`in2.m4/')
137 AT_DATA([in2.m4],
138 [[sinclude(`in2.m4/')
139 sinclude(`.')
141 AT_DATA([in3.m4],
142 [[include(`.')
145 AT_CHECK_M4([in1.m4/], [1], [], [stderr])
146 dnl mingw fails with EINVAL rather than the expected ENOTDIR
147 AT_CHECK([$SED 's/Invalid argument/Not a directory/' stderr], [0],
148 [[m4: cannot open `in1.m4/': Not a directory
151 AT_CHECK_M4([in1.m4], [1], [[
152 ]], [stderr])
153 dnl mingw fails with EINVAL rather than the expected ENOTDIR
154 AT_CHECK([$SED 's/Invalid argument/Not a directory/' stderr], [0],
155 [[m4:in1.m4:1: include: cannot open `in2.m4/': Not a directory
158 AT_CHECK_M4([in2.m4], [0], [[
162 AT_CHECK_M4([in3.m4], [1], [[
163 ]], [stderr])
164 dnl mingw fails with EACCES rather than the expected EISDIR
165 AT_CHECK([$SED 's/Permission denied/Is a directory/' stderr], [0],
166 [[m4:in3.m4:1: include: cannot open `.': Is a directory
169 AT_CLEANUP
172 ## ------- ##
173 ## foreach ##
174 ## ------- ##
176 AT_SETUP([foreach])
178 AT_DATA([[foreach.m4]],
179 [[divert(-1)
180 # foreach(x, (item_1, item_2, ..., item_n), stmt)
181 define(`foreach', `pushdef(`$1', `')_foreach($@)popdef(`$1')')
182 define(`_arg1', ``$1'')
183 define(`_foreach',
184        `ifelse($2, `()', ,
185                `define(`$1', `_arg1$2')$3`'_foreach(`$1', `(shift$2)', `$3')')')
187 # traceon(`define', `foreach', `_foreach', `ifelse')
189 define(a, 1)
190 define(b, 2)
191 define(c, 3)
192 divert
193 foreach(`x', `(foo, bar, foobar)', `Word was: x
196 # Quote torture from Akim Demaille <akim@epita.fr>
197 foreach(`x', `(`a', `(b', `c)')', `Word was: x
200 # Something more complex, from Pierre Gaumond <gaumondp@ere.umontreal.ca>.
201 define(`case', `  $1)
202     $2=" -$1";;
203 ')dnl
204 define(`_cat', `$1$2')dnl
205 `case' "$1" in
206 foreach(`x', ((a, vara), (b, varb), (c, varc)), `_cat(`case', x)')dnl
207 esac
210 AT_CHECK_M4([foreach.m4], 0,
212 Word was: foo
213 Word was: bar
214 Word was: foobar
217 # Quote torture from Akim Demaille <akim@epita.fr>
218 Word was: a
219 Word was: (b
220 Word was: c)
223 # Something more complex, from Pierre Gaumond <gaumondp@ere.umontreal.ca>.
224 case "$1" in
225   1)
226     vara=" -1";;
227   2)
228     varb=" -2";;
229   3)
230     varc=" -3";;
231 esac
234 AT_CLEANUP
238 ## ------- ##
239 ## forloop ##
240 ## ------- ##
242 AT_SETUP([forloop])
244 AT_DATA([[forloop.m4]],
245 [[divert(-1)
246 # forloop(i, from, to, stmt)
248 define(`forloop', `pushdef(`$1', `$2')_forloop(`$1', `$2', `$3', `$4')popdef(`$1')')
249 define(`_forloop',
250        `$4`'ifelse($1, `$3', ,
251                          `define(`$1', incr($1))_forloop(`$1', `$2', `$3', `$4')')')
252 divert
253 forloop(`x', 1, 10, `2**x = eval(2**x)
257 AT_CHECK_M4([forloop.m4], 0,
259 2**1 = 2
260 2**2 = 4
261 2**3 = 8
262 2**4 = 16
263 2**5 = 32
264 2**6 = 64
265 2**7 = 128
266 2**8 = 256
267 2**9 = 512
268 2**10 = 1024
272 AT_CLEANUP
276 ## ----- ##
277 ## fstab ##
278 ## ----- ##
280 AT_SETUP([fstab])
282 AT_DATA([[fstab.m4]],
283 [[define(`concat', `translit(``$*'', `   ')')
284 define(`fsent', `format(`%-25s %-16s nfs    %-16s 0 0', `$1:$2', `$3', concat$4)')
286 fsent(freja, /home/gevn, /home/gevn, (rw, soft, bg, grpid))
287 fsent(freja, /home/freja, /home/freja, (rw, soft, grpid))
288 fsent(rimfaxe, /home/rimfaxe, /home/rimfaxe, (rw, soft, bg))
292 AT_CHECK_M4([fstab.m4], 0,
296 freja:/home/gevn          /home/gevn       nfs    rw,soft,bg,grpid 0 0
297 freja:/home/freja         /home/freja      nfs    rw,soft,grpid    0 0
298 rimfaxe:/home/rimfaxe     /home/rimfaxe    nfs    rw,soft,bg       0 0
302 AT_CLEANUP
306 ## ----- ##
307 ## hanoi ##
308 ## ----- ##
310 AT_SETUP([hanoi])
312 AT_DATA([[hanoi.m4]],
313 [[divert(-1)
315 # move(from, to)
316 define(`move', `Move one disk from `$1' to `$2'.
319 # _hanoi (cnt, from, to, aux)
320 define(`_hanoi', `ifelse(eval(`$1'<=1), 1, `move($2, $3)',
321 `_hanoi(decr($1), $2, $4, $3)move($2, $3)_hanoi(decr($1), $4, $3, $2)')')
323 # hanoi (cnt)
324 define(`hanoi', `_hanoi(`$1', source, destination, auxilliary)')
326 # traceon(`move', `_hanoi', `decr')
327 divert`'dnl
329 hanoi(3)
332 AT_CHECK_M4([hanoi.m4], 0,
334 Move one disk from source to destination.
335 Move one disk from source to auxilliary.
336 Move one disk from destination to auxilliary.
337 Move one disk from source to destination.
338 Move one disk from auxilliary to source.
339 Move one disk from auxilliary to destination.
340 Move one disk from source to destination.
344 AT_CLEANUP
347 ## ------ ##
348 ## ifndef ##
349 ## ------ ##
351 AT_SETUP([ifndef])
353 dnl This catches a bug added 2008-03-13, fixed 2008-04-10.
354 AT_DATA([in.m4],
355 [[define(`ifndef', `ifdef(`$1', `$3', `$2')')dnl
356 define(`a_really_long_name', `1')dnl
357 ifdef(`divnum', `yes', `no')
358 ifndef(`divnum', `yes', `no')
359 ifdef(`ifndef', `yes', `no')
360 ifndef(`ifndef', `yes', `no')
361 ifdef(`a_really_long_name', `yes', `no')
362 ifndef(`a_really_long_name', `yes', `no')
363 ifdef(`no_such', `yes', `no')
364 ifndef(`no_such', `yes', `no')
367 AT_CHECK_M4([in.m4], [0],
368 [[yes
378 AT_CLEANUP
381 ## ------- ##
382 ## iso8859 ##
383 ## ------- ##
385 AT_SETUP([iso8859])
387 # Eh eh eh...
388 # We can't embed iso8859.m4 in here since it includes a NUL character,
389 # and we can't yet rely on autom4te being NUL-clean (even though this
390 # test shows that M4 is trying to be NUL-clean).
392 AT_DATA([[expout]],
393 [[# Testing quotes
394 DEFINE                  # eol
395 CHANGEQUOTE(«,»)        # eol
396 0 TEST                  # TEST
397 1 test                  # test
398 2 Â«test»                # Â«test»
399 3 Â«Â«test»»              # Â«Â«test»»
400 CHANGEQUOTE(«««,»»»)    # eol
401 0 TEST                  # TEST
402 1 Â«TEST»                # Â«TEST»
403 2 Â«Â«TEST»»              # Â«Â«TEST»»
404 3 test                  # test
405 # Test use of all iso8859 characters except ^Z (win32 EOF) and NUL  ` '
406 Length of string is: 254
407 Comparing strings: MATCH
408 # NUL passes through now!
412 AT_CHECK_M4(["$abs_srcdir/iso8859.m4"], 0, expout)
414 AT_CLEANUP
417 ## ------------- ##
418 ## nul character ##
419 ## ------------- ##
421 AT_SETUP([nul character])
423 # Operating on a binary file is a GNU sed extension.
424 AT_CHECK([test `printf 'a\0b\n' | $SED s/a.b/abc/ | wc -c` = 4 dnl
425 || { echo "skipping: $SED can't handle NUL"; exit 77; }])
427 # We don't embed null.* in here, since it is harder to guarantee the
428 # behavior of NUL through autom4te.
429 $SED "s|null.m4|$abs_srcdir/null.m4|" < "$abs_srcdir/null.out" > expout
430 $SED "s|null.m4|$abs_srcdir/null.m4|" < "$abs_srcdir/null.err" > experr
432 dnl all but m4exit
433 AT_CHECK_M4([-Dm4exit -I "$abs_srcdir" null.m4], [1], [expout], [experr])
435 dnl just m4exit
436 AT_CHECK_M4(["$abs_srcdir/null.m4"], [1],
437 [[# This file tests m4 behavior on NUL bytes.
438 ]], [stderr])
439 AT_CHECK([sed "s|$abs_srcdir/||" stderr], [0],
440 [[m4:null.m4:5: Warning: m4exit: non-numeric argument `2\0002'
443 AT_CLEANUP
446 ## --------- ##
447 ## recursion ##
448 ## --------- ##
450 AT_SETUP([recursion])
452 dnl This input exploits contents of loop.m4 to print out the final value
453 dnl of the recursion.
454 AT_DATA([in.m4],
455 [[define(`foo', `divert`'len(popdef(`_foreachq')_foreachq($@))')dnl
456 define(`debug', `pushdef(`_foreachq', defn(`foo'))')dnl
457 include(`loop.m4')dnl
460 dnl boxed recursion
461 AT_CHECK_M4([-I "$top_srcdir/examples" -Dlimit=10 -Dverbose loop.m4], [0],
462 [[ 1 2 3 4 5 6 7 8 9 10
464 AT_CHECK_M4([-I "$top_srcdir/examples" -Dlimit=2500 loop.m4], [0])
465 AT_CHECK_M4([-I "$top_srcdir/examples" -Dlimit=10000 in.m4], [0], [[48894
468 dnl unboxed recursion
469 AT_CHECK_M4([-I "$top_srcdir/examples" -Dlimit=10 -Dverbose -Dalt loop.m4], [0],
470 [[ 1 2 3 4 5 6 7 8 9 10
472 AT_CHECK_M4([-I "$top_srcdir/examples" -Dlimit=2500 -Dalt loop.m4], [0])
473 AT_CHECK_M4([-I "$top_srcdir/examples" -Dlimit=10000 -Dalt in.m4], [0],
474 [[48894
477 dnl foreach via forloop recursion
478 AT_CHECK_M4([-I "$top_srcdir/examples" -Dlimit=10 -Dverbose -Dalt=4 loop.m4],
479 [0], [[ 1 2 3 4 5 6 7 8 9 10
481 AT_CHECK_M4([-I "$top_srcdir/examples" -Dlimit=2500 -Dalt=4 loop.m4], [0])
482 AT_CHECK_M4([-I "$top_srcdir/examples" -Dlimit=10000 -Dalt=4 in.m4], [0],
483 [[48894
486 dnl foreach via definition stack
487 AT_DATA([in.m4], [[include(`forloop3.m4')include(`stack_sep.m4')dnl
488 forloop(`i', `1', `10000', `pushdef(`s', i)')dnl
489 define(`colon', `:')define(`dash', `-')dnl
490 len(stack_foreach_sep(`s', `dash', `', `colon'))
492 AT_CHECK_M4([-I "$top_srcdir/examples" in.m4], [0], [[58893
495 AT_CLEANUP
498 ## ------- ##
499 ## reverse ##
500 ## ------- ##
502 AT_SETUP([reverse])
504 AT_DATA([[reverse.m4]],
505 [[define(`reverse', `ifelse(eval($# > 1), 1, `reverse(shift($@)), `$1'', ``$1'')')
506 ``'' => reverse.
507 ``hej'' => reverse(hej).
508 ``hej, med, dig'' => reverse(hej, med, dig).
511 AT_CHECK_M4([reverse.m4], 0,
513 `' => .
514 `hej' => hej.
515 `hej, med, dig' => dig, med, hej.
518 AT_CLEANUP
521 ## ------------- ##
522 ## stderr closed ##
523 ## ------------- ##
525 AT_SETUP([stderr closed])
527 dnl no error when stderr is not used
528 AT_CHECK_M4([2>&-], [0])
530 dnl no error when stderr is not used
531 AT_DATA([in.m4], [[hello world
533 AT_CHECK_M4([2>&-], [0], [[hello world
534 ]], [], [in.m4])
536 dnl must exit nonzero when error issued
537 AT_CHECK_M4([--unknown 2>&-], [1])
539 dnl must exit nonzero if stderr used
540 AT_DATA([in.m4], [[errprint(`hello world
541 ')dnl
543 AT_CHECK_M4([2>&-], [1], [], [], [in.m4])
545 dnl must exit nonzero if stderr used
546 AT_DATA([in.m4], [[hello
547 dnl(`world')
549 AT_CHECK_M4([2>&-], [1], [[hello
550 ]], [], [in.m4])
552 dnl must exit nonzero on error, in spite of m4exit requesting 0
553 AT_DATA([in.m4], [[errprint(`hello world
554 ')m4exit(`0')
556 AT_CHECK_M4([2>&-], [1], [], [], [in.m4])
558 dnl preserve m4exit's failure value
559 AT_DATA([in.m4], [[errprint(`hello world
560 ')m4exit(`2')
562 AT_CHECK_M4([2>&-], [2], [], [], [in.m4])
564 dnl trace file must not collide with closed stderr
565 AT_DATA([in.m4], [[errprint(`hello world
566 ')dnl
568 AT_CHECK_M4([--debugfile=trace -terrprint 2>&-], [1], [], [], [in.m4])
569 AT_CHECK([cat trace], [0], [[m4trace: -1- errprint(`hello world
570 ') -> `'
573 dnl spilled diversion file must not collide with closed stderr
574 AT_DATA([in.m4], [M4_ONE_MEG_DEFN[divert(1)f
575 and`'dnl(not)
576 divert
577 hello`'dnl(world)
578 undivert
579 goodbye
581 AT_CHECK_M4([2>&-], [1], [stdout-nolog], [], [in.m4])
582 AT_CHECK([$SED -ne '/./p' stdout], [0],
583 [[hello
585 goodbye
588 dnl command line input file must not collide with closed stderr
589 AT_DATA([in.m4], [[syscmd(`echo <&2')ifelse(sysval,
590 `0', `skipping: sh cannot detect closed fds
591 m4exit(`77')')
593 AT_CHECK_M4([2>&-], [0], [ignore], [ignore], [in.m4])
594 AT_DATA([in.m4], [[syscmd(`cat <&2')sysval
595 dnl this line should not be read by cat
597 AT_CHECK_M4([2>&-], [0], [[1
598 ]], [], [in.m4])
599 AT_CHECK_M4([in.m4 2>&-], [0], [[1
602 AT_CLEANUP
605 ## ------------ ##
606 ## stdin closed ##
607 ## ------------ ##
609 AT_SETUP([stdin closed])
611 dnl no error when stdin is not used due to early exit
612 AT_CHECK_M4([--version], [0], [ignore], [], [-])
614 dnl no error when stdin is not used due to supplied file
615 AT_DATA([in.m4], [[hello world
617 AT_CHECK_M4([in.m4], [0], [[hello world
618 ]], [], [-])
620 dnl Some systems reopen closed stdin to /dev/null, particularly when using
621 dnl the shell script tests/m4 instead of a binary src/m4.
622 AT_CHECK([cat <&- && { echo "skipping: can't detect closed stdin"; exit 77; }],
623 [1], [], [stderr])
624 mv stderr experr
625 AT_DATA([in.m4], [[syscmd(`cat')ifelse(sysval,
626 `0', `skipping: unable to start with closed stdin
627 m4exit(`77')')
629 AT_CHECK_M4([in.m4], [0], [ignore], [ignore], [-])
631 dnl error when stdin must be read
632 AT_CHECK_M4([], [1], [],
633 [[m4:stdin:1: error reading `stdin'
634 m4: error closing file: Bad file descriptor
635 ]], [-])
637 dnl error when stdin must be read
638 AT_CHECK_M4([-], [1], [],
639 [[m4:stdin:1: error reading `stdin'
640 m4: error closing file: Bad file descriptor
641 ]], [-])
643 dnl error once per command-line attempt to read stdin
644 AT_DATA([in.m4], [[hello world
646 AT_CHECK_M4([- in.m4 -], [1], [[hello world
647 ]], [[m4:stdin:1: error reading `stdin'
648 m4:stdin:1: error reading `stdin'
649 m4: error closing file: Bad file descriptor
650 ]], [-])
652 dnl command line and trace file must not collide with stdin
653 AT_DATA([in.m4], [[syscmd(`cat')dnl
655 AT_CHECK_M4([--debugfile=trace -tdnl in.m4], [0], [], [experr], [-])
656 AT_CHECK([cat trace], [0], [[m4trace: -1- dnl -> `'
659 dnl diversions must not collide with stdin
660 AT_DATA([in.m4], [M4_ONE_MEG_DEFN[divert(`1')f
661 syscmd(`cat')dnl
662 divert(`-1')undivert
664 AT_CHECK_M4([in.m4], [0], [], [experr], [-])
666 dnl diversions must not collide with stdin
667 AT_DATA([in.m4], [M4_ONE_MEG_DEFN[hello divert(`1')f
669 AT_DATA([in2.m4], [[divert(`-1')undivert
670 divert`'world
672 AT_CHECK_M4([in.m4 - in2.m4], [1], [[hello world
673 ]], [[m4:stdin:1: error reading `stdin'
674 m4: error closing file: Bad file descriptor
675 ]], [-])
677 AT_CLEANUP
679 ## -------------- ##
680 ## stdin seekable ##
681 ## -------------- ##
683 AT_SETUP([stdin seekable])
685 dnl POSIX requires that if stdin is seekable, m4 must seek to the location
686 dnl of unprocessed data for the benefit of other copies of the fd.
688 dnl Check internal follow-on process.
689 AT_DATA([in.m4], [[syscmd(`cat')m4exit(15)
691 AT_CHECK_M4([], [0], [[m4exit(15)
692 ]], [], [in.m4])
694 dnl Check external follow-on process, after m4exit.
695 AT_DATA([in.m4], [[m4exit(
696 0)trailing data
698 AT_CHECK([($M4; cat) < in.m4], [0], [[trailing data
701 dnl Check external follow-on process, after fatal error.
702 dnl We can't use AT_CHECK_M4, so we must post-process stderr ourselves.
703 AT_DATA([in.m4], [[dnl(
704 0)trailing data
706 AT_CHECK([($M4 -EE; cat) < in.m4], [0], [[trailing data
707 ]], [stderr])
708 AT_CHECK([[$SED 's/^[^:]*[lt-]*m4[.ex]*:/m4:/' stderr]], [0],
709 [[m4:stdin:1: Warning: dnl: extra arguments ignored: 1 > 0
712 dnl Not all sed and libc combinations get the remaining tests right (for
713 dnl example, sed 4.1.4 on glibc, or cygwin 1.5.22 and earlier).
714 AT_CHECK([($SED -ne 1q; cat) < in.m4], [0], [stdout])
715 AT_CHECK([test "x`cat stdout`" = "x0)trailing data" || \
716   { echo "skipping: $SED is too greedy on seekable stdin"; exit 77; }])
718 dnl Ensure that esyscmd resumes parsing where the child process left off.
719 AT_DATA([in.m4], [[define(`foo', `FOO')m4 foo
720 esyscmd(`$SED -e "s/foo/bar/;q"')sed foo
721 m4 foo
723 AT_CHECK_M4([], [0], [[m4 FOO
724 sed bar
725 m4 FOO
726 ]], [], [in.m4])
728 dnl Ensure that syscmd resumes parsing where the child process left off.
729 AT_DATA([in.m4], [[define(`foo', `FOO')m4 foo
730 syscmd(`$SED -e "s/foo/bar/;q"')sed foo
731 m4 foo
733 AT_CHECK_M4([], [0], [[m4 FOO
734 sed bar
735 m4 FOO
736 ]], [], [in.m4])
738 AT_CLEANUP
740 ## ------------- ##
741 ## stdout closed ##
742 ## ------------- ##
744 AT_SETUP([stdout closed])
746 dnl error when stdout must be used
747 AT_CHECK_M4([--version >&-], [1], [],
748 [[m4: write error: Bad file descriptor
751 dnl no error when stdout is not used
752 AT_CHECK_M4([>&-], [0])
754 dnl no error when stdout is not used
755 AT_DATA([in.m4], [[errprint(`hello world
756 ')dnl
758 AT_CHECK_M4([>&-], [0], [], [[hello world
759 ]], [in.m4])
761 dnl error when stdout must be used
762 AT_CHECK_M4([-P >&-], [1], [],
763 [[m4: write error: Bad file descriptor
764 ]], [in.m4])
766 dnl error must occur in spite of m4exit requesting 0
767 AT_DATA([in.m4], [[hello world
768 m4exit(`0')
770 AT_CHECK_M4([>&-], [1], [],
771 [[m4:stdin:2: write error: Bad file descriptor
772 ]], [in.m4])
774 dnl preserve m4exit's failure value
775 AT_DATA([in.m4], [[hello world
776 m4exit(`2')
778 AT_CHECK_M4([>&-], [2], [],
779 [[m4:stdin:2: write error: Bad file descriptor
780 ]], [in.m4])
782 dnl trace file must not collide with closed stdout
783 AT_DATA([in.m4], [[hello world
786 AT_CHECK_M4([--debugfile=trace -tdnl >&-], [1], [],
787 [[m4: write error: Bad file descriptor
788 ]], [in.m4])
789 AT_CHECK([cat trace], [0], [[m4trace: -1- dnl -> `'
792 dnl esyscmd always has valid stdout
793 AT_DATA([in.m4], [[errprint(esyscmd(`echo hello'))dnl
795 AT_CHECK_M4([>&-], [0], [], [[hello
796 ]], [in.m4])
798 dnl syscmd inherits closed stdout
799 AT_DATA([hi], [[hi
801 AT_CHECK([cat hi >&- && { echo "skipping: can't detect closed stdout"; exit 77; }],
802 [1], [], [stderr])
803 AT_CHECK([$SED 's/Bad file number/Bad file descriptor/' < stderr > experr])
804 AT_DATA([in.m4], [[syscmd(`cat hi')dnl
806 AT_CHECK_M4([>&-], [0], [], [experr], [in.m4])
808 dnl spilled diversion file must not collide with closed stdout
809 AT_DATA([in.m4], [M4_ONE_MEG_DEFN[divert(1)f
810 syscmd(`cat hi')
811 divert(`-1')undivert
813 AT_CHECK_M4([>&-], [0], [], [experr], [in.m4])
815 dnl command line input file must not collide with closed stdout
816 AT_DATA([in.m4], [[syscmd(`echo <&2')ifelse(sysval,
817 `0', `skipping: sh cannot detect closed fds
818 m4exit(`77')')
820 AT_CHECK_M4([2>&-], [0], [ignore], [ignore], [in.m4])
821 AT_DATA([in.m4], [[syscmd(`cat <&1 >&2')dnl
822 dnl this line should not be read by cat
824 AT_CHECK_M4([in.m4 >&-], [0], [], [stderr])
825 AT_CHECK([[$SED -e 's/.*[Bb]\(ad file descriptor\)$/B\1/' stderr]], [0],
826 [[Bad file descriptor
829 AT_CLEANUP
832 ## ----------- ##
833 ## stdout full ##
834 ## ----------- ##
836 AT_SETUP([stdout full])
837 AT_CHECK([test -w /dev/full && test -c /dev/full || {
838   echo "skipping: no /dev/full support";
839   exit 77
842 dnl Be careful when modifying these tests.  Writes that exceed stdio buffering
843 dnl limits trigger different but legal behavior where errno is lost.  Tests
844 dnl that currently require "No space left on device" may fail if the amount of
845 dnl output changes.  The --help test shows how to handle this.
847 dnl detect write failures on --help
848 AT_CHECK_M4([--help >/dev/full], [1], [], [stderr])
849 AT_CHECK([grep '^m4: write error' stderr], [0], [ignore])
851 dnl detect write failures on --version
852 AT_CHECK_M4([--version >/dev/full], [1], [],
853 [[m4: write error: No space left on device
856 dnl detect ordinary write failures
857 AT_DATA([in.m4], [[hello world
859 AT_CHECK_M4([in.m4 >/dev/full], [1], [],
860 [[m4: write error: No space left on device
863 dnl detect stderr write failures
864 AT_DATA([in.m4], [[dnl(hello world)
866 AT_CHECK_M4([in.m4 2>/dev/full], [1])
868 dnl detect trace write failures
869 AT_DATA([in.m4], [[dnl
871 AT_CHECK_M4([-tdnl in.m4 2>/dev/full], [1])
873 dnl detect trace write failures
874 AT_DATA([in.m4], [[dnl
876 AT_CHECK_M4([--debugfile=/dev/full -tdnl in.m4], [1], [],
877 [[m4: error writing to debug stream: No space left on device
880 dnl too hard to test for spilled diversion failures, without requiring the
881 dnl user to have a nearly full partition that we can assign to $TMPDIR.
883 dnl write failures must override m4exit requesting 0
884 AT_DATA([in.m4], [[hello world m4exit(`0')
886 AT_CHECK_M4([in.m4 >/dev/full], [1], [],
887 [[m4:in.m4:1: write error: No space left on device
890 dnl preserve m4exit's failure value
891 AT_DATA([in.m4], [[hello world m4exit(`2')
893 AT_CHECK_M4([in.m4 >/dev/full], [2], [],
894 [[m4:in.m4:1: write error: No space left on device
897 AT_CLEANUP
900 ## --------- ##
901 ## sysv-args ##
902 ## --------- ##
904 AT_SETUP([sysv-args])
906 AT_DATA([[sysv-args.m4]],
907 [[divert(-1)
908 define(`nargs', `$#')
909 define(`concat', `ifelse(1, $#, `$1', `$1` 'concat(shift($@))')')
910 traceon(`concat', `nargs')
911 divert
913 nargs
914 nargs()
915 nargs(1,2,3,4,5,6)
917 concat()
918 concat(`hej', `med', `dig')
919 concat(`hej', `med', `dig', `en gang igen')
920 concat(an, awful, lot, of, argument, at, least, more, that, ten, silly, arguments)
923 AT_DATA([[expout]],
931 hej med dig
932 hej med dig en gang igen
933 an awful lot of argument at least more that ten silly arguments
936 AT_DATA([[experr]],
937 [[m4trace: -1- nargs -> `0'
938 m4trace: -1- nargs(`') -> `1'
939 m4trace: -1- nargs(`1', `2', `3', `4', `5', `6') -> `6'
940 m4trace: -1- concat(`') -> `ifelse(1, 1, `', `` 'concat(shift(`'))')'
941 m4trace: -1- concat(`hej', `med', `dig') -> `ifelse(1, 3, `hej', `hej` 'concat(shift(`hej',`med',`dig'))')'
942 m4trace: -1- concat(`med', `dig') -> `ifelse(1, 2, `med', `med` 'concat(shift(`med',`dig'))')'
943 m4trace: -1- concat(`dig') -> `ifelse(1, 1, `dig', `dig` 'concat(shift(`dig'))')'
944 m4trace: -1- concat(`hej', `med', `dig', `en gang igen') -> `ifelse(1, 4, `hej', `hej` 'concat(shift(`hej',`med',`dig',`en gang igen'))')'
945 m4trace: -1- concat(`med', `dig', `en gang igen') -> `ifelse(1, 3, `med', `med` 'concat(shift(`med',`dig',`en gang igen'))')'
946 m4trace: -1- concat(`dig', `en gang igen') -> `ifelse(1, 2, `dig', `dig` 'concat(shift(`dig',`en gang igen'))')'
947 m4trace: -1- concat(`en gang igen') -> `ifelse(1, 1, `en gang igen', `en gang igen` 'concat(shift(`en gang igen'))')'
948 m4trace: -1- concat(`an', `awful', `lot', `of', `argument', `at', `least', `more', `that', `ten', `silly', `arguments') -> `ifelse(1, 12, `an', `an` 'concat(shift(`an',`awful',`lot',`of',`argument',`at',`least',`more',`that',`ten',`silly',`arguments'))')'
949 m4trace: -1- concat(`awful', `lot', `of', `argument', `at', `least', `more', `that', `ten', `silly', `arguments') -> `ifelse(1, 11, `awful', `awful` 'concat(shift(`awful',`lot',`of',`argument',`at',`least',`more',`that',`ten',`silly',`arguments'))')'
950 m4trace: -1- concat(`lot', `of', `argument', `at', `least', `more', `that', `ten', `silly', `arguments') -> `ifelse(1, 10, `lot', `lot` 'concat(shift(`lot',`of',`argument',`at',`least',`more',`that',`ten',`silly',`arguments'))')'
951 m4trace: -1- concat(`of', `argument', `at', `least', `more', `that', `ten', `silly', `arguments') -> `ifelse(1, 9, `of', `of` 'concat(shift(`of',`argument',`at',`least',`more',`that',`ten',`silly',`arguments'))')'
952 m4trace: -1- concat(`argument', `at', `least', `more', `that', `ten', `silly', `arguments') -> `ifelse(1, 8, `argument', `argument` 'concat(shift(`argument',`at',`least',`more',`that',`ten',`silly',`arguments'))')'
953 m4trace: -1- concat(`at', `least', `more', `that', `ten', `silly', `arguments') -> `ifelse(1, 7, `at', `at` 'concat(shift(`at',`least',`more',`that',`ten',`silly',`arguments'))')'
954 m4trace: -1- concat(`least', `more', `that', `ten', `silly', `arguments') -> `ifelse(1, 6, `least', `least` 'concat(shift(`least',`more',`that',`ten',`silly',`arguments'))')'
955 m4trace: -1- concat(`more', `that', `ten', `silly', `arguments') -> `ifelse(1, 5, `more', `more` 'concat(shift(`more',`that',`ten',`silly',`arguments'))')'
956 m4trace: -1- concat(`that', `ten', `silly', `arguments') -> `ifelse(1, 4, `that', `that` 'concat(shift(`that',`ten',`silly',`arguments'))')'
957 m4trace: -1- concat(`ten', `silly', `arguments') -> `ifelse(1, 3, `ten', `ten` 'concat(shift(`ten',`silly',`arguments'))')'
958 m4trace: -1- concat(`silly', `arguments') -> `ifelse(1, 2, `silly', `silly` 'concat(shift(`silly',`arguments'))')'
959 m4trace: -1- concat(`arguments') -> `ifelse(1, 1, `arguments', `arguments` 'concat(shift(`arguments'))')'
962 AT_CHECK_M4([sysv-args.m4], 0, [expout], [experr])
964 AT_CLEANUP