diff options
Diffstat (limited to 'tests/m4sugar.at')
-rw-r--r-- | tests/m4sugar.at | 2140 |
1 files changed, 2140 insertions, 0 deletions
diff --git a/tests/m4sugar.at b/tests/m4sugar.at new file mode 100644 index 0000000..997e2dd --- /dev/null +++ b/tests/m4sugar.at @@ -0,0 +1,2140 @@ +# -*- Autotest -*- + +AT_BANNER([M4sugar.]) + +# Copyright (C) 2000-2002, 2005-2012 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +# AT_CHECK_M4SUGAR_TEXT(CODE, STDOUT, STDERR) +# ------------------------------------------- +# Check that m4sugar CODE expands to STDOUT and emits STDERR. +m4_define([AT_CHECK_M4SUGAR_TEXT], +[ +AT_DATA_M4SUGAR([script.4s], +[[m4_init +m4_divert_push([])[]dnl +]$1[[]dnl +m4_divert_pop([]) +]]) + +AT_CHECK_M4SUGAR([-o-],, [$2], [$3]) +])# AT_CHECK_M4SUGAR_TEXT + + +## ------------------ ## +## m4_stack_foreach. ## +## ------------------ ## + +AT_SETUP([m4@&t@_stack]) + +AT_KEYWORDS([m4@&t@_stack_foreach m4@&t@_stack_foreach_lifo]) +AT_KEYWORDS([m4@&t@_stack_foreach_sep m4@&t@_stack_foreach_sep_lifo]) +AT_KEYWORDS([m4@&t@_copy m4@&t@_n]) + +# Test the semantics of macros to walk stacked macro definitions. +AT_CHECK_M4SUGAR_TEXT([[dnl +m4_pushdef([abc], [def])dnl +m4_pushdef([abc], [ghi])dnl +m4_pushdef([abc], [jkl])dnl +m4_stack_foreach([abc], [m4_n]) +abc +m4_stack_foreach_lifo([abc], [m4_n]) +m4_stack_foreach([abc], [m4_n]) +m4_copy([abc], [foo])dnl +m4_stack_foreach([foo], [m4_n]) +m4_stack_foreach_lifo([foo], [m4_n]) +m4_stack_foreach_sep([abc], [ m4_index([abcdefghijkl],], [)]) +m4_define([colon], [:])m4_define([lt], [<])m4_define([gt], [>])dnl +m4_stack_foreach_sep_lifo([abc], [lt], [gt], [colon]) +m4_pushdef([xyz], [123])dnl +m4_pushdef([xyz], [456])dnl +m4_define([doit], [[$1](m4_stack_foreach_sep([xyz], [m4_dquote(], [)], [,])) +])dnl +m4_stack_foreach([abc], [doit])]], +[[def +ghi +jkl + +jkl +jkl +ghi +def + +def +ghi +jkl + +def +ghi +jkl + +jkl +ghi +def + + 3 6 9 +<jkl>:<ghi>:<def> +def([123],[456]) +ghi([123],[456]) +jkl([123],[456]) +]]) + +AT_CLEANUP + + +## --------- ## +## m4_defn. ## +## --------- ## + +AT_SETUP([m4@&t@_defn]) + +AT_KEYWORDS([m4@&t@_popdef m4@&t@_undefine m4@&t@_copy m4@&t@_rename +m4@&t@_copy_force m4@&t@_rename_force]) + +# Ensure that m4sugar dies when dereferencing undefined macros, whether +# this is provided by m4 natively or faked by wrappers in m4sugar. + +AT_DATA_M4SUGAR([script.4s], +[[m4_define([good]) +m4_defn([good], [oops]) +]]) + +AT_CHECK_M4SUGAR([-o-], 1, [], [stderr]) +AT_CHECK([grep good stderr], [1]) +AT_CHECK([grep 'm4@&t@_defn: undefined.*oops' stderr], [0], [ignore]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_define([good]) +m4_popdef([good], [oops]) +]]) + +AT_CHECK_M4SUGAR([-o-], 1, [], [stderr]) +AT_CHECK([grep good stderr], [1]) +AT_CHECK([grep 'm4@&t@_popdef: undefined.*oops' stderr], [0], [ignore]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_define([good]) +m4_undefine([good], [oops]) +]]) + +AT_CHECK_M4SUGAR([-o-], 1, [], [stderr]) +AT_CHECK([grep good stderr], [1]) +AT_CHECK([grep 'm4@&t@_undefine: undefined.*oops' stderr], [0], [ignore]) + +# Cannot rename an undefined macro. +AT_DATA_M4SUGAR([script.4s], +[[m4_rename([oops], [good]) +]]) + +AT_CHECK_M4SUGAR([-o-], 1, [], [stderr]) +AT_CHECK([grep 'm4@&t@_undefine: undefined.*oops' stderr], [0], [ignore]) + +# Check that pushdef stacks can be renamed. +AT_CHECK_M4SUGAR_TEXT([[m4_pushdef([a], [1])dnl +m4_pushdef([a], [2])dnl +m4_pushdef([a], m4_defn([m4_divnum]))dnl +a b c +m4_rename([a], [b])dnl +a b c +m4_copy([b], [c])dnl +a b c +m4_popdef([b], [c])dnl +a b c +m4_popdef([b], [c])dnl +a b c +m4_popdef([b], [c])dnl +a b c +dnl m4_copy is intentionally a no-op on undefined source +m4_copy([oops], [dummy])m4_ifdef([dummy], [[oops]])dnl +dnl allow forceful overwrites +m4_define([d], [4])m4_define([e], [5])m4_define([f], [6])dnl +m4_copy_force([d], [e])dnl +m4_rename_force([d], [f])dnl +d e f +m4_popdef([e], [f])dnl +d e f +]], [[0 b c +a 0 c +a 0 0 +a 2 2 +a 1 1 +a b c +d 4 4 +d e f +]]) + +AT_CLEANUP + + +## ------------ ## +## m4_dumpdef. ## +## ------------ ## + +AT_SETUP([m4@&t@_dumpdef]) + +AT_KEYWORDS([m4@&t@_dumpdefs]) + +# Ensure that m4sugar dies when dereferencing undefined macros. + +AT_DATA_M4SUGAR([script.4s], +[[m4_define([good], [yep]) +m4_dumpdef([good], [oops]) +]]) + +AT_CHECK_M4SUGAR([-o-], 1, [], [stderr]) +AT_CHECK([grep '^good: \[[yep\]]$' stderr], [0], [ignore]) +AT_CHECK([grep 'm4@&t@_dumpdef: undefined.*oops' stderr], [0], [ignore]) + +# Check that pushdef stacks can be dumped. +AT_CHECK_M4SUGAR_TEXT([[m4_divert_push([KILL]) +m4_pushdef([a], [1]) +m4_pushdef([a], [2]) +m4_dumpdef([a]) +m4_dumpdefs([oops], [a]) +m4_divert_pop([KILL])dnl +]], [], +[[a: [2] +a: [2] +a: [1] +]]) + +# Check behavior when dumping builtins. Unfortunately, when using M4 1.4.x +# (or more precisely, when __m4_version__ is undefined), builtins get +# flattened to an empty string. It takes M4 1.6 to work around this. +AT_DATA_M4SUGAR([script.4s], +[[m4_ifdef([__m4_version__], [_m4_undefine([__m4_version__])]) +m4_init +m4_dumpdef([m4_define]) +]]) + +AT_CHECK_M4SUGAR([-o-], [0], [], +[[m4_define: [] +]]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_init +m4_ifdef([__m4_version__], +[m4_dumpdef([m4_define])], +[m4_errprintn([m4_define: <define>])]) +]]) + +AT_CHECK_M4SUGAR([-o-], [0], [], +[[m4_define: <define> +]]) + +AT_CLEANUP + + +## --------- ## +## m4_warn. ## +## --------- ## + +AT_SETUP([m4@&t@_warn]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_init +m4_defun([cross_warning], [m4_warn([cross], [cross])]) + +m4_divert([0])dnl +m4_warn([obsolete], [obsolete])dnl +cross_warning[]dnl +m4_warn([syntax], [syntax])dnl +cross_warning[]dnl +m4_warn([syntax], [syntax])dnl +]]) + +AT_CHECK_M4SUGAR([-o-], 0, [], +[script.4s:4: warning: prefer named diversions +script.4s:7: warning: syntax +script.4s:9: warning: syntax +]) + +AT_CHECK_M4SUGAR([-o- -Wall], 0, [], +[script.4s:4: warning: prefer named diversions +script.4s:5: warning: obsolete +script.4s:6: warning: cross +script.4s:2: cross_warning is expanded from... +script.4s:6: the top level +script.4s:7: warning: syntax +script.4s:8: warning: cross +script.4s:2: cross_warning is expanded from... +script.4s:8: the top level +script.4s:9: warning: syntax +]) + +AT_CHECK_M4SUGAR([-o- -Wnone,cross], 0, [], +[script.4s:6: warning: cross +script.4s:2: cross_warning is expanded from... +script.4s:6: the top level +script.4s:8: warning: cross +script.4s:2: cross_warning is expanded from... +script.4s:8: the top level +]) + +AT_CHECK_M4SUGAR([-o- -Wnone,cross,error], 1, [], +[[script.4s:6: warning: cross +script.4s:2: cross_warning is expanded from... +script.4s:6: the top level +script.4s:8: warning: cross +script.4s:2: cross_warning is expanded from... +script.4s:8: the top level +]]) + +AT_CLEANUP + + +## ----------------- ## +## m4_divert_stack. ## +## ----------------- ## + +AT_SETUP([m4@&t@_divert_stack]) +AT_KEYWORDS([m4@&t@_divert m4@&t@_divert_push m4@&t@_divert_pop +m4@&t@_undivert m4@&t@_cleardivert m4@&t@_divert_text]) + +dnl This test names some diversions to avoid a warning. +AT_CHECK_M4SUGAR_TEXT([[m4_define([_m4_divert(ten)], [10])dnl +m4_define([_m4_divert(twenty)], [20])dnl +m4_define([_m4_divert(thirty)], [30])dnl +1.m4_divert_stack +m4_divert_push([ten])2.m4_divert_stack +m4_divert_text([twenty], [3.m4_divert_stack])dnl +m4_divert([thirty])4.m4_divert_stack +m4_divert_pop([thirty])dnl +5.m4_undivert([twenty], [thirty]) +m4_pattern_allow([^m4_divert])dnl +]], [[1.script.4s:2: m4@&t@_divert_push: +script.4s:1: m4@&t@_divert: KILL +5.3.script.4s:8: m4@&t@_divert_push: twenty +script.4s:7: m4@&t@_divert_push: ten +script.4s:2: m4@&t@_divert_push: +script.4s:1: m4@&t@_divert: KILL +4.script.4s:9: m4@&t@_divert: thirty +script.4s:2: m4@&t@_divert_push: +script.4s:1: m4@&t@_divert: KILL + +2.script.4s:7: m4@&t@_divert_push: ten +script.4s:2: m4@&t@_divert_push: +script.4s:1: m4@&t@_divert: KILL +]]) + +AT_CHECK_M4SUGAR_TEXT([[dnl +m4_divert_text([3], [three])dnl +m4_divert_text([4], [four])dnl +m4_divert_text([1], [one])dnl +m4_divert_text([2], [two])dnl +m4_cleardivert([2], [3])dnl +]], +[[one +four +]], +[[script.4s:4: warning: prefer named diversions +script.4s:5: warning: prefer named diversions +script.4s:6: warning: prefer named diversions +script.4s:7: warning: prefer named diversions +script.4s:8: warning: prefer named diversions +]]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_divert_pop +]]) +AT_CHECK_M4SUGAR([-o-], [1], [], +[[script.4s:1: error: too many m4@&t@_divert_pop +script.4s:1: the top level +autom4te: m4 failed with exit status: 1 +]]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_init +m4_divert_push([1]) +m4_divert_pop([2]) +]]) +AT_CHECK_M4SUGAR([-o-], [1], [], +[[script.4s:3: error: m4@&t@_divert_pop(2): diversion mismatch: +script.4s:2: m4@&t@_divert_push: 1 +script.4s:1: m4@&t@_divert: KILL +script.4s:3: the top level +autom4te: m4 failed with exit status: 1 +]]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_divert([1]) +m4_init +m4_divert_push([2]) +]]) +AT_CHECK_M4SUGAR([-o-], [1], [], +[[script.4s:2: error: m4@&t@_init: unbalanced m4@&t@_divert_push: +script.4s:3: m4@&t@_divert_push: 2 +script.4s:2: m4@&t@_divert: KILL +script.4s:2: the top level +autom4te: m4 failed with exit status: 1 +]]) + +AT_CLEANUP + + +## -------------------- ## +## m4_expansion_stack. ## +## -------------------- ## + +AT_SETUP([m4@&t@_expansion_stack]) + +AT_CHECK_M4SUGAR_TEXT([[1.m4_expansion_stack +m4_defun([a], [b])dnl +m4_define([c], [d])dnl +m4_defun([d], [2.m4_expansion_stack])dnl +m4_defun([b], [c])dnl +a +3.m4_ifdef([_m4_expansion_stack], [m4_expansion_stack]) +]], [[1.script.4s:3: the top level +2.script.4s:6: d is expanded from... +script.4s:7: b is expanded from... +script.4s:4: a is expanded from... +script.4s:8: the top level +3. +]]) + +AT_CLEANUP + + +## --------------------------- ## +## m4_require: error message. ## +## --------------------------- ## + +AT_SETUP([m4@&t@_require: error message]) +AT_KEYWORDS([m4@&t@_require]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_defun([foo], [FOO]) +m4_require([foo]) +]]) + +AT_CHECK_M4SUGAR([], 1, [], +[[script.4s:2: error: m4@&t@_require(foo): cannot be used outside of an m4_defun'd macro +script.4s:2: the top level +autom4te: m4 failed with exit status: 1 +]]) +AT_CLEANUP + + +## ----------------------------------- ## +## m4_require: circular dependencies. ## +## ----------------------------------- ## + +AT_SETUP([m4@&t@_require: circular dependencies]) +AT_KEYWORDS([m4@&t@_require]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_defun([foo], [m4_require([bar])]) + +m4_defun([bar], [m4_require([foo])]) + +m4_defun([baz], [m4_require([foo])]) + +m4_init +m4_divert([0])dnl +baz +]]) + +AT_CHECK_M4SUGAR([], 1, [], +[[script.4s:9: error: m4@&t@_require: circular dependency of foo +script.4s:3: bar is expanded from... +script.4s:1: foo is expanded from... +script.4s:5: baz is expanded from... +script.4s:9: the top level +autom4te: m4 failed with exit status: 1 +]]) +AT_CLEANUP + + +## ---------------------- ## +## m4_require: one-shot. ## +## ---------------------- ## + +AT_SETUP([m4@&t@_require: one-shot initialization]) +AT_KEYWORDS([m4@&t@_require]) +AT_KEYWORDS([m4@&t@_defun_init m4@&t@_copy m4@&t@_defun_once]) + +dnl check out m4_defun_init, m4_copy, and odd macro names +AT_CHECK_M4SUGAR_TEXT([[ +m4_define([t], [text])dnl +m4_defun_init([a], [[init a +]], [[common a] t])dnl +m4_defun([b], [[b]m4_require([a])])dnl +m4_defun([c], [[c]m4_require([a])])dnl +b +c +a()dnl + +m4_defun_init([-], [hello, ], [m4_if([$#], [0], [world], [[$1]])])dnl +m4_copy([-], [.])dnl +m4_indir([.]) +m4_indir([.], [goodbye]) +m4_indir([-], [again]) +]], [[ +init a +common a text +b +c +common a text +hello, world +goodbye +hello, again +]]) + +dnl Check m4_defun_once behavior +AT_CHECK_M4SUGAR_TEXT([[ +m4_defun_once([a], [[a]])dnl +m4_defun([b], [[b]m4_require([a])])dnl +m4_defun([c], [[c]a[]m4_require([b])])dnl +c +a +m4_defun_once([d], [[d]m4_require([a])])dnl +d +m4_defun_once([e], [[e]])dnl +m4_defun([f], [[f]m4_require([e])e])dnl +f +]], [[ +a +b +c + +d +e +f +]]) + + +AT_CLEANUP + + +## -------------------- ## +## m4_require: nested. ## +## -------------------- ## + +AT_SETUP([m4@&t@_require: nested]) +AT_KEYWORDS([m4@&t@_require m4@&t@_defun]) + +dnl From the m4sugar.m4 discourse: Require chains, top level +AT_CHECK_M4SUGAR_TEXT([[dnl +m4_defun([a], [[a]])dnl aka TEST2a +m4_defun([b], [[b]m4_require([a])])dnl aka TEST3 +m4_defun([c], [[c]m4_require([b])])dnl aka TEST2b +m4_defun([d], [[d]m4_require([a])m4_require([c])])dnl aka TEST1 +pre +d +d +post +]], +[[pre +a +b +c +d +d +post +]]) + +dnl From the m4sugar.m4 discourse: Require chains, nested +AT_CHECK_M4SUGAR_TEXT([[dnl +m4_defun([a], [[a]])dnl aka TEST2a +m4_defun([b], [[b]m4_require([a])])dnl aka TEST3 +m4_defun([c], [[c]m4_require([b])])dnl aka TEST2b +m4_defun([d], [[d]m4_require([a])m4_require([c])])dnl aka TEST1 +m4_defun([wrap], +[pre +d +d +post])dnl +wrap +]], +[[a +b +c +pre +d +d +post +]]) + +dnl Direct invocation, nested requires, top level +AT_CHECK_M4SUGAR_TEXT([[dnl +m4_defun([a], [[a]])dnl +m4_defun([b], [[b]m4_require([a])])dnl +m4_defun([c], [[c]m4_require([b])])dnl +pre +a +c +a +c +post +]], +[[pre +a +b +c +a +c +post +]]) + +dnl Direct invocation, nested requires, nested defun. This is an example +dnl of expansion before requirement, such that b occurs before its +dnl prerequisite a. This indicates a bug in the macros (but not in +dnl autoconf), so we should be emitting a warning. +AT_CHECK_M4SUGAR_TEXT([[dnl +m4_defun([a], [[a]])dnl +m4_defun([b], [[b]m4_require([a])])dnl +m4_defun([c], [[c]m4_require([b])])dnl +dnl the extra macro layer works around line number differences in older m4 +m4_define([foo], [m4_defun([outer], +[pre +a +c +a +c +post])])foo[]dnl +outer +]], +[[a +b +pre +a +c +a +c +post +]], +[[script.4s:15: warning: m4@&t@_require: `a' was expanded before it was required +script.4s:15: http://www.gnu.org/software/autoconf/manual/autoconf.html#Expanded-Before-Required +script.4s:5: b is expanded from... +script.4s:6: c is expanded from... +script.4s:14: outer is expanded from... +script.4s:15: the top level +]]) + +dnl Direct invocation, expand-before-require but no nested require. As this +dnl is common in real life, but does not result in out-of-order expansion, +dnl we silently permit this. +AT_CHECK_M4SUGAR_TEXT([[dnl +m4_defun([a], [[a]])dnl +m4_defun([b], [[b]m4_require([a])])dnl +m4_defun([c], [[c]])dnl +m4_defun([d], [[d]m4_require([c])])dnl +pre1 +a +b +a +b +post1 +m4_defun([outer], +[pre2 +c +d +c +d +post2])dnl +outer +m4_defun([e], [[e]])dnl +m4_defun([f], [[f]m4_require([e])])dnl +m4_defun([g], [[g] +e +f])dnl +m4_defun([h], [[h]m4_require([g])])dnl +h +m4_defun([i], [[i]])dnl +m4_defun([j], [[j] +i])dnl +m4_defun([k], [[k]m4_require([i])])dnl +m4_defun([l], [[l]m4_require([k])])dnl +m4_defun([m], [[m]m4_require([j])m4_require([l])])dnl +m +]], +[[pre1 +a +b +a +b +post1 +pre2 +c +d +c +d +post2 +g +e +f +h +j +i +k +l +m +]]) + +AT_CLEANUP + + +## ------------------------------------------------- ## +## m4_ifval, m4_ifblank, m4_ifset, m4_default, etc. ## +## ------------------------------------------------- ## + +AT_SETUP([m4sugar shorthand conditionals]) +AT_KEYWORDS([m4@&t@_ifval m4@&t@_ifblank m4@&t@_ifnblank m4@&t@_ifset +m4@&t@_default m4@&t@_default_quoted m4@&t@_default_nblank +m4@&t@_default_nblank_quoted]) + +AT_CHECK_M4SUGAR_TEXT([[m4_define([active], [ACTIVE])m4_define([empty]) +m4_ifval([active], [yes], [no]) +m4_ifval([empty], [yes], [no]) +m4_ifval([ ], [yes], [no]) +m4_ifval([], [yes], [no]) +m4_ifblank([active], [yes], [no]) +m4_ifblank([empty], [yes], [no]) +m4_ifblank([ ], [yes], [no]) +m4_ifblank([], [yes], [no]) +m4_ifnblank([active], [yes], [no]) +m4_ifnblank([empty], [yes], [no]) +m4_ifnblank([ ], [yes], [no]) +m4_ifnblank([], [yes], [no]) +m4_ifset([active], [yes], [no]) +m4_ifset([empty], [yes], [no]) +m4_ifset([ ], [yes], [no]) +m4_ifset([], [yes], [no]) +--- +m4_define([demo1], [m4_default([$1], [$2])])dnl +m4_define([demo2], [m4_default_quoted([$1], [$2])])dnl +m4_define([demo3], [m4_default_nblank([$1], [$2])])dnl +m4_define([demo4], [m4_default_nblank_quoted([$1], [$2])])dnl +demo1([active], [default]) +demo1([], [active]) +demo1([empty], [text]) +-demo1([ ], [active])- +demo2([active], [default]) +demo2([], [active]) +demo2([empty], [text]) +-demo2([ ], [active])- +demo3([active], [default]) +demo3([], [active]) +demo3([empty], [text]) +-demo3([ ], [active])- +demo4([active], [default]) +demo4([], [active]) +demo4([empty], [text]) +-demo4([ ], [active])- +]], [[ +yes +yes +yes +no +no +no +yes +yes +yes +yes +no +no +yes +no +no +no +--- +ACTIVE +ACTIVE + +- - +active +active +empty +- - +ACTIVE +ACTIVE + +-ACTIVE- +active +active +empty +-active- +]]) + +AT_CLEANUP + +## --------- ## +## m4_cond. ## +## --------- ## + +AT_SETUP([m4@&t@_cond]) + +AT_CHECK_M4SUGAR_TEXT([[m4_define([side], [m4_errprintn([$1])$1]) +m4_cond([side(1)], [1], [a], + [side(1)], [1], [b], + [side(1)], [2], [c]) +m4_cond([side(2)], [1], [a], + [side(2)], [1], [b], + [side(2)], [2], [c], + [side(2)]) +m4_cond([side(3)], [1], [a], + [side(3)], [1], [b], + [side(3)], [2], [c], + [side(3)]) +m4_cond([a,a], [a,a], [yes], [no]) +m4_cond([[a,a]], [a,a], [yes]) +m4_cond([a,a], [a,b], [yes], [no]) +m4_cond([a,a], [a,b], [yes]) +m4_cond([m4_eval([0xa])]) +m4_define([ab], [AB])dnl +m4_cond([a])b +m4_cond([1], [1], [a])b +m4_cond([1], [2], [3], [a])b +]], [[ +a +c +3 +yes +yes +no + +10 +AB +AB +AB +]], [[1 +2 +2 +2 +3 +3 +3 +3 +]]) + +AT_CLEANUP + + +## ---------- ## +## m4 lists. ## +## ---------- ## + +AT_SETUP([m4 lists]) + +AT_KEYWORDS([m4@&t@_car m4@&t@_cdr m4@&t@_argn _m4@&t_cdr]) + +AT_CHECK_M4SUGAR_TEXT([[dnl +m4_define([a], [A])m4_define([b], [B])m4_define([c], [C]) +m4_argn([1], [a], [b], [c]) +m4_argn([2], [a], [b], [c]) +m4_argn([3], [a], [b], [c]) +m4_argn([4], [a], [b], [c]) +m4_car([a], [b], [c]) +m4_cdr([a], [b], [c]) +m4_cdr([a], [b]) +m4_cdr([a]) +_m4_cdr([a], [b], [c]) +_m4_cdr([a], [b]) +_m4_cdr([a]) +m4_if(m4_cdr([], []), [[]], [good], [bad]) +m4_if(m4_cdr([]), [], [good], [bad]) +]], [[ +a +b +c + +a +[b],[c] +[b] + +, [b],[c] +, [b] + +good +good +]]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_init +m4_argn([0], [a], [b], [c]) +]]) +AT_CHECK_M4SUGAR([-o-], [1], [], +[[script.4s:2: error: assert failed: 0 < 0 +script.4s:2: the top level +autom4te: m4 failed with exit status: 1 +]]) + +AT_CLEANUP + + +## ---------- ## +## m4_split. ## +## ---------- ## + +AT_SETUP([m4@&t@_split]) + +AT_CHECK_M4SUGAR_TEXT( +[[m4_define([active], [ACT, IVE])m4_define([bd], [oops]) +m4_split +m4_split([[]]) +m4_split([ ]) +m4_split([active]) +m4_split([ active active ])end +m4_split([ ], [ ]) +m4_split([active], [ ]) +m4_split([ active active ], [ ])end +m4_split([abcde], [bd]) +m4_split([abcde], [[bd]]) +m4_split([foo=`` bar='']) +m4_split([foo='' bar=``]) +dnl these next two are from the manual; keep this in sync if the internal +dnl quoting strings in m4_split are changed +m4_define([a], [A])m4_define([b], [B])m4_define([c], [C])dnl +m4_split([a )}>=- b -=<{( c]) +m4_split([a )}@&t@>=- b -=<@&t@{( c]) +]], +[[ + +[[]] +[], [] +[active] +[], [active], [active], []end +[], [] +[active] +[], [active active], []end +[abcde] +[a], [c], [e] +[foo=``], [bar=''] +[foo=''], [bar=``] +[a], [], [B], [], [c] +[a], [)}>=@&t@-], [b], [-@&t@=<{(], [c] +]]) + +AT_CLEANUP + + +## ------- ## +## m4_do. ## +## ------- ## + +AT_SETUP([m4@&t@_do]) + +AT_CHECK_M4SUGAR_TEXT( +[[m4_define([ab], [1])m4_define([bc], [2])m4_define([abc], [3])dnl +m4_define([AB], [4])m4_define([BC], [5])m4_define([ABC], [6])dnl +m4_do +m4_do([a]) +m4_do([a], [b])c +m4_unquote(m4_join([], [a], [b]))c +m4_define([a], [A])m4_define([b], [B])m4_define([c], [C])dnl +m4_do([a], [b])c +m4_unquote(m4_join([], [a], [b]))c +]], +[[ +a +abc +3 +ABC +3 +]]) + +AT_CLEANUP + + +## ----------- ## +## m4_append. ## +## ----------- ## + +AT_SETUP([m4@&t@_append]) +AT_KEYWORDS([m4@&t@_append_uniq m4@&t@_append_uniq_w]) + +AT_CHECK_M4SUGAR_TEXT( +[[m4_define([active], [ACTIVE])dnl +m4_append([sentence], [This is an])dnl +m4_append([sentence], [ active ])dnl +m4_append([sentence], [symbol.])dnl +sentence +m4_undefine([active])dnl +sentence +m4_define([active], [ACTIVE])dnl +m4_append([hooks], [m4_define([act1], [act2])])dnl +m4_append([hooks], [m4_define([act2], [active])])dnl +m4_undefine([active])dnl +act1 +hooks +act1 +dnl Test for bug fixed in 2.62 when separator is active. +m4_define([a], [A])dnl +m4_append_uniq([foo], [-], [a])dnl +m4_append_uniq([foo], [-], [a])dnl +m4_append_uniq([bar], [-], [a])dnl +m4_append_uniq([bar], [~], [a])dnl +m4_append_uniq([bar], [-], [a])dnl +m4_defn([foo]) +m4_defn([bar]) +foo +bar +m4_append_uniq([blah], [one], [, ], [new], [existing]) +m4_append_uniq([blah], [two], [, ], [new], [existing]) +m4_append_uniq([blah], [two], [, ], [new], [existing]) +m4_append_uniq([blah], [three], [, ], [new], [existing]) +m4_append([blah], [two], [, ])dnl +blah +m4_dquote(blah) +m4_append([list], [one], [[, ]])dnl +m4_append([list], [two], [[, ]])dnl +m4_append([list], [three], [[, ]])dnl +list +m4_dquote(list) +m4_append_uniq_w([numbers], [1 1 2])dnl +m4_append_uniq_w([numbers], [ 2 3 ])dnl +numbers +]], +[[This is an ACTIVE symbol. +This is an active symbol. +act1 + +active +- +-a~ +- +-A~ +new +new +existing +new +one, two, three, two +[one],[two],[three],[two] +one, two, three +[one, two, three] +1 2 3 +]]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_init[]dnl +m4_append_uniq([str], [a], [ ]) +m4_append_uniq([str], [a b], [ ]) +m4_divert([])dnl +str +]]) + +AT_CHECK_M4SUGAR([-o-], 0, [[a a b +]], [[script.4s:3: warning: m4@&t@_append_uniq: `a b' contains ` ' +]]) + +AT_CLEANUP + + +## --------- ## +## m4_join. ## +## --------- ## + +AT_SETUP([m4@&t@_join]) + +AT_KEYWORDS([m4@&t@_joinall]) + +AT_CHECK_M4SUGAR_TEXT( +[[m4_define([active], [ACTIVE]) +m4_join +m4_join([|]) +m4_join([, ], [one], [two]) +m4_dquote(m4_join([, ], [one], [two])) +m4_join([|], [active], [active]) +m4_join([|], ,,,[one]) +m4_join([|], [one],,,) +m4_join([], ,,,[two]) +m4_join([], [two],,,) +m4_join([ active ], [one], , [two]) +m4_join([], [one], [two]) +m4_joinall([-], [one], [], [two]) +m4_joinall([-], [], [], [three], [], []) +m4_joinall([], [one], [], [two]) +m4_joinall +m4_joinall([-]) +m4_joinall([-], [one]) +]], +[[ + + +one, two +[one, two] +active|active +one +one +two +two +one active two +onetwo +one--two +--three-- +onetwo + + +one +]]) + +AT_CLEANUP + + +## ----------- ## +## m4_expand. ## +## ----------- ## + +AT_SETUP([m4@&t@_expand]) + +AT_CHECK_M4SUGAR_TEXT( +[[m4_define([active], [ACTIVE])dnl +m4_expand([#active +active]) +m4_expand([[active]]) +dnl properly quoted case statements +m4_expand([case a in @%:@( + *) echo active, ;; +esac +case b in + *[)] echo active, ;; +esac]) +dnl unbalanced underquoted `)', but we manage anyway (gasp!) +m4_expand([case c in #( + *) echo active, ;; +esac +case d in + *) echo active, ;; +esac]) +dnl unterminated comment/dnl +m4_expand([active # active]) +m4_expand([a +dnl]) +m4_expand([a +-dnl]) +]], +[[#active +ACTIVE +active +case a in #( + *) echo ACTIVE, ;; +esac +case b in + *) echo ACTIVE, ;; +esac +case c in #( + *) echo ACTIVE, ;; +esac +case d in + *) echo ACTIVE, ;; +esac +ACTIVE # active +a +a +- +]]) + +AT_CLEANUP + + +## ------------- ## +## m4_text_box. ## +## ------------- ## + +AT_SETUP([m4@&t@_text_box]) + +AT_CHECK_M4SUGAR_TEXT([[ +m4_text_box([a $1 @&t@b]) +m4_text_box([a $1 @&t@b], [$]) +m4_text_box([a $1 @&t@b], [,]) +]], [[ +## ------ ## +## a $1 b ## +## ------ ## +## $$$$$$ ## +## a $1 b ## +## $$$$$$ ## +## ,,,,,, ## +## a $1 b ## +## ,,,,,, ## +]]) + +AT_CLEANUP + +## -------------- ## +## m4_text_wrap. ## +## -------------- ## + +AT_SETUP([m4@&t@_text_wrap]) +AT_KEYWORDS([m4@&t@_escape]) + +# m4_text_wrap is used to display the help strings. Also, check that +# commas and $ are not swallowed. This can easily happen because of +# m4-listification. + +AT_DATA_M4SUGAR([script.4s], +[[m4_init[]m4_divert([])dnl +m4_define([a], [OOPS])dnl +m4_escape([a[b $c#]d]) +m4_if(m4_escape([a[b $c#]d]), [a[b $c#]d], [oops], + m4_escape([a[b $c#]d]), [a@<:@b @S|@c@%:@@:>@d], [pass], [oops]) + +m4_text_wrap([Short string */], [ ], [/* ], 20) + +m4_text_wrap([Much longer string */], [ ], [/* ], 20) + +m4_text_wrap([Short doc.], [ ], [ --short ], 30) + +m4_text_wrap([Short doc.], [ ], [ --too-wide], 30) + +m4_text_wrap([Super long documentation.], [ ], [ --too-wide], 30) + +m4_text_wrap([First, second , third, [,quoted space]]) +m4_define([xfff], [oops]) +m4_text_wrap([Some $1 $2 $3 $4 embedded dollars.], [ $* ], [ $@ ], [0xfff & 20]) +]]) + +AT_DATA([expout], +[[a[b $c#]d +pass + +/* Short string */ + +/* Much longer + string */ + + --short Short doc. + + --too-wide + Short doc. + + --too-wide + Super long + documentation. + +First, second , third, [,quoted space] + + $@ Some $1 $2 $3 + $* $4 embedded + $* dollars. +]]) + +AT_CHECK_M4SUGAR([-o-], 0, [expout]) + +AT_CLEANUP + +## -------------------- ## +## m4_version_compare. ## +## -------------------- ## + +AT_SETUP([m4@&t@_version_compare]) + +AT_KEYWORDS([m4@&t@_list_cmp]) + +AT_CHECK_M4SUGAR_TEXT( +[[m4_version_compare([1.1], [2.0]) +m4_version_compare([2.0b], [2.0a]) +m4_version_compare([2.0z], [2.0y]) +m4_version_compare([1.1.1], [1.1.1a]) +m4_version_compare([1.2], [1.1.1a]) +m4_version_compare([1.0], [1]) +m4_version_compare([1.0a], [1.0a]) +m4_version_compare([1.1a], [1.1a.1]) +m4_version_compare([1.10], [1.1a]) +m4_version_compare([1-1a], [1,1A]) +m4_define([a], [oops])dnl +m4_version_compare([1.1a], [1.1A]) +m4_version_compare([1z], [1aa]) +m4_version_compare([2.61a], [2.61a-248-dc51]) +m4_version_compare([2.61b], [2.61a-248-dc51]) +m4_version_compare([08], [09]) +m4_version_compare([010], [8]) +dnl Test that side effects to m4_list_cmp occur exactly once +m4_list_cmp([[0], [0], [0]m4_errprintn([hi])], + [[0], [0], [0]m4_errprintn([hi])]) +m4_list_cmp([[0], [0], [0]m4_errprintn([hi])], + [[0], [0], [0]m4_errprintn([bye])]) +]], +[[-1 +1 +1 +-1 +1 +0 +0 +-1 +1 +0 +0 +-1 +-1 +1 +-1 +1 +0 +0 +]], [[hi +hi +hi +bye +]]) + +AT_CLEANUP + +## ------------------------------ ## +## Standard regular expressions. ## +## ------------------------------ ## + +AT_SETUP([Standard regular expressions]) + +# AT_CHECK_M4RE(RE-NAME, TEXT, INTENT = `ok' | `') +# ------------------------------------------------ +# Check whether RE-NAME (a macro whose definition is a regular expression) +# matches TEXT. INTENT = `ok' if the match should succeed or else empty. +m4_define([AT_CHECK_M4RE], +[AT_CHECK_M4SUGAR_TEXT( +[[m4_bregexp([$2], ^m4_defn([$1])$, [ok]) +]], [$3 +])]) + +AT_CHECK_M4RE([m4_re_word], [ab9_c], [ok]) +AT_CHECK_M4RE([m4_re_word], [_9abc], [ok]) +AT_CHECK_M4RE([m4_re_word], [9ab_c]) + +AT_CHECK_M4RE([m4_re_string], [ab9_c], [ok]) +AT_CHECK_M4RE([m4_re_string], [_9abc], [ok]) +AT_CHECK_M4RE([m4_re_string], [9ab_c], [ok]) +AT_CHECK_M4RE([m4_re_string], [9a@_c]) + +AT_CLEANUP + +## ----------- ## +## m4_bmatch. ## +## ----------- ## + +AT_SETUP([m4@&t@_bmatch]) + +AT_CHECK_M4SUGAR_TEXT( +[[m4_bmatch([abc], [default\]) +m4_bmatch([abc], [^a], [yes]) +m4_bmatch([abc], [^a], [yes], [no]) +m4_bmatch([abc], [^.a], [yes]) +m4_bmatch([abc], [^.a], [yes], [no\]) +m4_bmatch([abc], [a], [1], [b], [2]) +m4_bmatch([abc], [A], [1], [b], [2]) +m4_define([ab], [AB])dnl +m4_bmatch([$*], [a])b +m4_bmatch([$*], [\*], [a])b +m4_bmatch([$*], [1], [2], [a])b +]], [[default\ +yes +yes + +no\ +1 +2 +AB +AB +AB +]]) + +AT_CLEANUP + +## ------------------------ ## +## m4_toupper, m4_tolower. ## +## ------------------------ ## + +AT_SETUP([m4@&t@_toupper and m4@&t@_tolower]) + +AT_CHECK_M4SUGAR_TEXT( +[[m4_define([abc], [hI])m4_define([ABC], [Hi]) +m4_toupper(abc aBc ABC) +m4_tolower(abc aBc ABC) +m4_toupper([abc aBc ABC]) +m4_tolower([abc aBc ABC]) +m4_echo(m4_toupper(abc aBc ABC)) +m4_echo(m4_tolower(abc aBc ABC)) +m4_echo(m4_toupper([abc aBc ABC])) +m4_echo(m4_tolower([abc aBc ABC])) +m4_do(m4_toupper(abc aBc ABC)) +m4_do(m4_tolower(abc aBc ABC)) +m4_do(m4_toupper([abc aBc ABC])) +m4_do(m4_tolower([abc aBc ABC])) +]], [[ +HI ABC HI +hi abc hi +ABC ABC ABC +abc abc abc +HI ABC HI +hi abc hi +ABC ABC ABC +abc abc abc +HI Hi HI +hi hI hi +Hi Hi Hi +hI hI hI +]]) + +AT_CLEANUP + +## --------------- ## +## m4_bpatsubsts. ## +## --------------- ## + +AT_SETUP([m4@&t@_bpatsubsts]) + +AT_CHECK_M4SUGAR_TEXT( +[[m4_bpatsubsts([11], [^..$]) +m4_bpatsubsts([11], [\(.\)1], [\12]) +m4_bpatsubsts([11], [^..$], [], [1], [2]) +m4_bpatsubsts([11], [\(.\)1], [\12], [1], [3]) +m4_define([a], [oops])m4_define([c], [oops])dnl +m4_define([AB], [good])m4_define([bc], [good])dnl +m4_bpatsubsts([abc], [a], [A], [b], [B], [c]) +m4_bpatsubsts([ab], [a])c +m4_bpatsubsts([ab], [c], [C], [a])c +m4_bpatsubsts([$1$*$@], [\$\*], [$#]) +]], [[11 +21 +22 +23 +good +good +good +$1$#$@ +]]) + +AT_CLEANUP + +## -------------- ## +## m4_esyscmd_s. ## +## -------------- ## + +AT_SETUP([m4@&t@_esyscmd_s]) +AT_KEYWORDS([m4@&t@_chomp m4@&t@_chomp_all]) + +AT_CHECK_M4SUGAR_TEXT( +[[m4_define([world], [WORLD])dnl +m4_chomp([abc]) +m4_chomp([world + +]) +m4_esyscmd_s([echo hello world]) +m4_esyscmd_s([echo '[goodbye, +cruel world + +]']) +]], [[abc +world + +hello WORLD +goodbye, +cruel world +]]) + +AT_CLEANUP + +## ---------- ## +## M4 Loops. ## +## ---------- ## + +AT_SETUP([M4 loops]) + +AT_KEYWORDS([m4@&t@_for m4@&t@_foreach m4@&t@_foreach_w m4@&t@_map_args_w]) + +AT_CHECK_M4SUGAR_TEXT([[dnl +m4_define([myvar], [outer value])dnl +m4_for([myvar], 1, 3, 1, [ myvar]) +m4_for([myvar], 1, 3, , [ myvar]) +m4_for([myvar], 3, 1,-1, [ myvar]) +m4_for([myvar], 3, 1, , [ myvar]) +m4_for([myvar], 1, 3, 2, [ myvar]) +m4_for([myvar], 3, 1,-2, [ myvar]) +m4_for([myvar],-1,-3,-2, [ myvar]) +m4_for([myvar],-3,-1, 2, [ myvar]) +dnl Make sure we recalculate the bounds correctly: +m4_for([myvar], 1, 3, 3, [ myvar]) +m4_for([myvar], 1, 6, 3, [ myvar]) +m4_for([myvar],22,-7,-5, [ myvar]) +m4_for([myvar],-2,-7,-4, [ myvar]) +m4_for([myvar],-7,-2, 4, [ myvar]) +dnl Make sure we are not exposed to division truncation: +m4_for([myvar], 2, 5, 2, [ myvar]) +m4_for([myvar],-5,-2, 2, [ myvar]) +m4_for([myvar], 5, 2,-2, [ myvar]) +m4_for([myvar],-2,-5,-2, [ myvar]) +dnl Make sure we do not divide by zero: +m4_for([myvar], 1, 1, , [ myvar]) +m4_for([myvar], 1, 1,+2, [ myvar]) +m4_for([myvar], 1, 1,-2, [ myvar]) +dnl Make sure we do not loop endlessly +m4_for([myval], 1, 1, 0, [ myval]) +dnl Make sure to properly parenthesize +m4_for([myvar], 3-5, -2+8, , [ myvar]) +m4_for([myvar], -2+8, 3-5, , [ myvar]) +m4_for([myvar], 8, 16, 3 * 2, [ myvar]) +m4_for([myvar], 8, 16, -3 * -2, [ myvar]) +m4_for([myvar], [2<<2], [2<<3], [-3 * (-2)], [ myvar]) +dnl Modifying var does not affect the number of iterations +m4_for([myvar], 1, 5, , [ myvar[]m4_define([myvar], 5)]) +dnl Make sure we can do nameless iteration +m4_for(, 1, 10, , -) +dnl foreach tests +m4_foreach([myvar], [[a], [b, c], [d], [e +],[f]], [ myvar|]) +m4_foreach_w([myvar], [a b c, d,e f +g], [ myvar|]) +myvar +m4_map_args_w([a b c, d,e f +g], [ ], [|]) +m4_map_args_w([a b], [\1], [/]) +m4_define([dashes], [--])dnl +m4_map_args_w([a b c], [/], [\1], [dashes]) +dnl only one side effect expansion, prior to visiting list elements +m4_foreach([i], [[1], [2], [3]m4_errprintn([hi])], [m4_errprintn(i)])dnl +dnl shifting forms an important part of loops +m4_shift3:m4_shift3(1,2,3):m4_shift3(1,2,3,4) +m4_shiftn(3,1,2,3):m4_shiftn(3,1,2,3,4) +]], +[[ 1 2 3 + 1 2 3 + 3 2 1 + 3 2 1 + 1 3 + 3 1 + -1 -3 + -3 -1 + 1 + 1 4 + 22 17 12 7 2 -3 + -2 -6 + -7 -3 + 2 4 + -5 -3 + 5 3 + -2 -4 + 1 + 1 + 1 + 1 + -2 -1 0 1 2 3 4 5 6 + 6 5 4 3 2 1 0 -1 -2 + 8 14 + 8 14 + 8 14 + 1 2 3 4 5 +---------- + a| b, c| d| e +| f| + a| b| c,| d,e| f| g| +outer value + a| b| c,| d,e| f| g| +\1a/\1b/ +/a\1--/b\1--/c\1 +::4 +:4 +]], [[hi +1 +2 +3 +]]) + +dnl bounds checking in m4_for +AT_DATA_M4SUGAR([script.4s], +[[m4_init +m4_divert([0])dnl +m4_for([myvar], 1, 3,-1, [ myvar]) +]]) +AT_CHECK_M4SUGAR([], 1, [], +[[script.4s:3: error: assert failed: -1 > 0 +script.4s:3: the top level +autom4te: m4 failed with exit status: 1 +]]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_init +m4_divert([0])dnl +m4_for([myvar], 1, 2, 0, [ myvar]) +]]) +AT_CHECK_M4SUGAR([], 1, [], +[[script.4s:3: error: assert failed: 0 > 0 +script.4s:3: the top level +autom4te: m4 failed with exit status: 1 +]]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_init +m4_divert([0])dnl +m4_for([myvar], 2, 1, 0, [ myvar]) +]]) +AT_CHECK_M4SUGAR([], 1, [], +[[script.4s:3: error: assert failed: 0 < 0 +script.4s:3: the top level +autom4te: m4 failed with exit status: 1 +]]) + +dnl m4_shiftn also does bounds checking +AT_DATA_M4SUGAR([script.4s], +[[m4_init +m4_divert([0])dnl +m4_shiftn(3,1,2) +]]) +AT_CHECK_M4SUGAR([], 1, [], +[[script.4s:3: error: assert failed: 0 < 3 && 3 < 3 +script.4s:3: the top level +autom4te: m4 failed with exit status: 1 +]]) + +AT_CLEANUP + + +## --------------------- ## +## m4_map{,all}{,_sep}. ## +## --------------------- ## + +AT_SETUP([m4@&t@_map]) +AT_KEYWORDS([m4@&t@_apply m4@&t@_map_sep m4@&t@_mapall m4@&t@_mapall_sep]) +AT_KEYWORDS([m4@&t@_count]) + +AT_CHECK_M4SUGAR_TEXT([[dnl +m4_map([m4_count], []) +m4_map([ m4_count], [[], + [[1]], + [[1], [2]]]) +m4_mapall([ m4_count], [[], + [[1]], + [[1], [2]]]) +m4_map_sep([m4_eval], [,], [[[1+2]], + [[10], [16]]]) +m4_count(m4_map_sep([m4_echo], [,], [[], [[1]], [[2]]])) +m4_count(m4_mapall_sep([m4_echo], [,], [[], [[1]], [[2]]])) +m4_map_sep([m4_eval], [[,]], [[[1+2]], + [[10], [16]]]) +m4_count(m4_map_sep([m4_echo], [[,]], [[], [[1]], [[2]]])) +m4_count(m4_mapall_sep([m4_echo], [[,]], [[], [[1]], [[2]]])) +m4_map([-], [[]]) +m4_mapall([-], [[]]) +m4_map_sep([-], [:], [[]]) +m4_mapall_sep([-], [:], [[]]) +m4_define([a], [m4_if([$#], [0], [oops], [$1], [a], [pass], [oops])])dnl +m4_define([a1], [oops])dnl +m4_define([pass1], [oops])dnl +m4_map([a], [[[a]]])1 +m4_map([m4_unquote([a])], [m4_dquote([a])]) +dnl only one side effect expansion, prior to visiting list elements +m4_map([m4_errprintn], [[[1]], [[2]], [[3]]m4_errprintn([hi])])dnl +m4_map_sep([m4_errprintn], [], [[[1]], [[2]], [[3]]m4_errprintn([hi])])dnl +m4_mapall([m4_errprintn], [[[1]], [[2]], [[3]]m4_errprintn([hi])])dnl +m4_mapall_sep([m4_errprintn], [], [[[1]], [[2]], [[3]]m4_errprintn([hi])])dnl +]], +[[ + 1 2 + 0 1 2 +3,a +2 +3 +3,a +1 +1 + +- + +- +pass1 +pass +]], [[hi +1 +2 +3 +hi +1 +2 +3 +hi +1 +2 +3 +hi +1 +2 +3 +]]) + +AT_CLEANUP + + +## --------------------------------------- ## +## m4_map_args{,_sep,_pair} and m4_curry. ## +## --------------------------------------- ## + +AT_SETUP([m4@&t@_map_args and m4@&t@_curry]) +AT_KEYWORDS([m4@&t@_map_args_sep m4@&t@_map_args_pair m4@&t@_reverse +m4@&t@_map]) + +dnl First, make sure we can curry in isolation. +AT_CHECK_M4SUGAR_TEXT( +[[m4_curry([m4_echo])([1]) +m4_curry([m4_curry], [m4_reverse], [1])([2])([3]) +m4_define([add], [m4_eval(([$1]) + ([$2]))])dnl +m4_define([add_one], [m4_curry([add], [1])])dnl +add_one()([4]) +]], +[[1 +3, 2, 1 +5 +]]) + +dnl Now, check that we can map a list of arguments. +AT_CHECK_M4SUGAR_TEXT([[m4_define([active], [ACTIVE])dnl +m4_map_args([ m4_echo]) +m4_map_args([ m4_echo], [plain], [active]) +m4_map_args([m4_unquote], [plain], [active]) +m4_map_args_pair([, m4_reverse], []) +m4_map_args_pair([, m4_reverse], [], [1]) +m4_map_args_pair([, m4_reverse], [], [1], [2]) +m4_map_args_pair([, m4_reverse], [], [1], [2], [3]) +m4_map_args_pair([, m4_reverse], [], [1], [2], [3], [4]) +m4_map_args_pair([, m4_reverse], [, m4_dquote], [1]) +m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2]) +m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3]) +m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3], [4]) +m4_map_args_sep([<], [>], [:], [1], [2], [3]) +m4_map_args_sep([m4_echo(], [)], [ ], [plain], [active]) +]], +[[ + plain active +plainACTIVE + +, 1 +, 2, 1 +, 2, 1, 3 +, 2, 1, 4, 3 +, [1] +, 2, 1 +, 2, 1, [3] +, 2, 1, 4, 3 +<1>:<2>:<3> +plain active +]]) + +dnl Finally, put the two concepts together, to show the real power of the API. +AT_CHECK_M4SUGAR_TEXT( +[[m4_define([add], [m4_eval(([$1]) + ([$2]))])dnl +m4_define([list], [[-1], [0], [1]])dnl +dnl list_add_n(value, arg...) +dnl add VALUE to each ARG and output the resulting list +m4_define([list_add_n], + [m4_shift(m4_map_args([,m4_curry([add], [$1])], m4_shift($@)))]) +list_add_n([1], list) +list_add_n([2], list) +]], [[ +0,1,2 +1,2,3 +]]) + +AT_CLEANUP + + +## ------------ ## +## m4_combine. ## +## ------------ ## + +AT_SETUP([m4@&t@_combine]) + +AT_CHECK_M4SUGAR_TEXT([[m4_define([a], [oops])dnl +m4_combine([, ], [[a], [b], [c]], [-], [1], [2], [3]) +m4_combine([, ], [[a], [b]], [-]) +m4_combine([, ], [[a], [b]], [-], []) +m4_combine([, ], [], [-], [a], [b]) +m4_combine([, ], [[]], [-], [a], [b]) +m4_combine([ a ], [[-], [+]], [a], [-], [+]) +m4_combine([$* ], [[$1], [$2]], [$#], [$@]) +]], +[[a-1, a-2, a-3, b-1, b-2, b-3, c-1, c-2, c-3 + +a-, b- + +-a, -b +-a- a -a+ a +a- a +a+ +$1$#$@$* $2$#$@ +]], []) + +AT_CLEANUP + + +## -------------- ## +## m4_{max,min}. ## +## -------------- ## + +AT_SETUP([m4@&t@_max and m4@&t@_min]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_max +]]) + +AT_CHECK_M4SUGAR([], 1, [], +[[script.4s:1: error: too few arguments to m4@&t@_max +script.4s:1: the top level +autom4te: m4 failed with exit status: 1 +]]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_min +]]) + +AT_CHECK_M4SUGAR([], 1, [], +[[script.4s:1: error: too few arguments to m4@&t@_min +script.4s:1: the top level +autom4te: m4 failed with exit status: 1 +]]) + +AT_CHECK_M4SUGAR_TEXT([[dnl +m4_min(0) +m4_min(0xa) +m4_min(0, 0) +m4_min(0, 1) +m4_min(1, 0) +m4_min(0+1, 1+1) +m4_min(0+1, 1+0) +m4_min(0, 1, 2) +m4_min(2, 1, 0) +m4_min(1m4_for([i], 2, 100, , [,i])) +m4_min(m4_for([i], 100, 2, , [i,])1) +---- +m4_max(0) +m4_max(0xa) +m4_max(0, 0) +m4_max(0, 1) +m4_max(1, 0) +m4_max(1+0, 1+1) +m4_max(1+0, 1+0) +m4_max(0, 1, 2) +m4_max(2, 1, 0) +m4_max(1m4_for([i], 2, 100, , [,i])) +m4_max(m4_for([i], 100, 2, , [i,])1) +]], +[[0 +10 +0 +0 +0 +1 +1 +0 +0 +1 +1 +---- +0 +10 +0 +1 +1 +2 +1 +2 +2 +100 +100 +]], []) + +AT_CLEANUP + + +## ----------- ## +## Recursion. ## +## ----------- ## + +AT_SETUP([recursion]) + +AT_KEYWORDS([m4@&t@_foreach m4@&t@_foreach_w m4@&t@_case m4@&t@_cond +m4@&t@_bpatsubsts m4@&t@_shiftn m4@&t@_do m4@&t@_dquote_elt m4@&t@_reverse +m4@&t@_map m4@&t@_join m4@&t@_joinall m4@&t@_list_cmp m4@&t@_max m4@&t@_min +m4@&t@_bmatch m4@&t@_map_args m4@&t@_map_args_pair]) + +dnl This test completes in a reasonable time if m4_foreach is linear, +dnl but thrashes if it is quadratic. If we are testing with m4 1.4.x, +dnl only the slower foreach.m4 implementation will work. But if we +dnl are testing with m4 1.6, we can rerun the test with __m4_version__ +dnl undefined to exercise the alternate code path. +AT_DATA_M4SUGAR([script.4s], +[[m4_init +m4_divert_push([])[]dnl +m4_len(m4_foreach_w([j], m4_do(m4_for([i], [1], [10000], [], [,i ])), [j ])) +m4_shiftn(9998m4_for([i], [1], [10000], [], [,i])) +m4_len(m4_join([--],, m4_dquote_elt(m4_for([i], [1], [10000], [], [,i])),)) +m4_len(m4_joinall([--], m4_map([, m4_echo], + m4_dquote([1]m4_for([i], [2], [10000], [], [,i]))))) +m4_max(m4_min([1]m4_for([i], [2], [10000], [], + [,i]))m4_for([i], [2], [10000], [], [,i])) +m4_case([10000]m4_for([i], [1], [10000], [], [,i]),[end]) +m4_list_cmp(m4_dquote(1m4_for([i], [2], [10000], [], [,i])), + m4_dquote(m4_reverse(10000m4_for([i], [9999], [1], [], [,i])), [0])) +m4_list_cmp([0], [0m4_for([i], [1], [10000], [], [,0])]) +m4_list_cmp([0m4_for([i], [1], [10000], [], [,0])], [0]) +m4_for([i], [1], [10000], [], [m4_define(i)])dnl +m4_undefine(1m4_for([i], [2], [10000], [], [,i]))dnl +m4_bpatsubsts([a1]m4_for([i], [1], [10000], [], [,i]), [a2], [A]) +m4_bmatch([9997]m4_for([i], [1], [10000], [], [,^i$])) +m4_define([up], [m4_define([$1], m4_incr($1))$1])m4_define([j], 0)dnl +m4_cond(m4_for([i], [1], [10000], [], [[up([j])], [9990], i,]) [oops]) j +m4_count(m4_map_args_pair([,m4_quote], []m4_map_args([,m4_echo]m4_for([i], + [1], [10000], [], [,i])))) +m4_divert_pop([]) +]]) + +AT_CHECK_M4SUGAR([-o-], [0], [[48894 +9999,10000 +78896 +58894 +10000 +end +0 +0 +0 +A +^9998$ +9990 9990 +5001 +]]) + +AT_DATA_M4SUGAR([script.4s], +[[m4_ifdef([__m4_version__], +[m4_undefine([__m4_version__])], +[m4_divert_push([])48894 +9999,10000 +78896 +58894 +10000 +end +0 +0 +0 +A +^9998$ +9990 9990 +5001 +m4_exit([0])]) +m4_init +m4_divert_push([])[]dnl +m4_len(m4_foreach_w([j], m4_do(m4_for([i], [1], [10000], [], [,i ])), [j ])) +m4_shiftn(9998m4_for([i], [1], [10000], [], [,i])) +m4_len(m4_join([--],, m4_dquote_elt(m4_for([i], [1], [10000], [], [,i])),)) +m4_len(m4_joinall([--], m4_map([, m4_echo], + m4_dquote([1]m4_for([i], [2], [10000], [], [,i]))))) +m4_max(m4_min([1]m4_for([i], [2], [10000], [], + [,i]))m4_for([i], [2], [10000], [], [,i])) +m4_case([10000]m4_for([i], [1], [10000], [], [,i]),[end]) +m4_list_cmp(m4_dquote(1m4_for([i], [2], [10000], [], [,i])), + m4_dquote(m4_reverse(10000m4_for([i], [9999], [1], [], [,i])), [0])) +m4_list_cmp([0], [0m4_for([i], [1], [10000], [], [,0])]) +m4_list_cmp([0m4_for([i], [1], [10000], [], [,0])], [0]) +m4_for([i], [1], [10000], [], [m4_define(i)])dnl +m4_undefine(1m4_for([i], [2], [10000], [], [,i]))dnl +m4_bpatsubsts([a1]m4_for([i], [1], [10000], [], [,i]), [a2], [A]) +m4_bmatch([9997]m4_for([i], [1], [10000], [], [,^i$])) +m4_define([up], [m4_define([$1], m4_incr($1))$1])m4_define([j], 0)dnl +m4_cond(m4_for([i], [1], [10000], [], [[up([j])], [9990], i,]) [oops]) j +m4_count(m4_map_args_pair([,m4_quote], []m4_map_args([,m4_echo]m4_for([i], + [1], [10000], [], [,i])))) +m4_divert_pop([]) +]]) + +AT_CHECK_M4SUGAR([-o-], [0], [[48894 +9999,10000 +78896 +58894 +10000 +end +0 +0 +0 +A +^9998$ +9990 9990 +5001 +]]) + +AT_CLEANUP + + +## ---------- ## +## m4_set_*. ## +## ---------- ## + +AT_SETUP([m4@&t@_set]) + +AT_KEYWORDS([m4@&t@_set_add m4@&t@_set_add_all m4@&t@_set_contains +m4@&t@_set_contents m4@&t@_set_delete m4@&t@_set_difference m4@&t@_set_dump +m4@&t@_set_empty m4@&t@_set_foreach m4@&t@_set_intersection m4@&t@_set_list +m4@&t@_set_listc m4@&t@_set_map m4@&t@_set_remove m4@&t@_set_size +m4@&t@_set_union]) + +# Simple tests +AT_CHECK_M4SUGAR_TEXT([[m4_set_contains([a], [1], [yes], [no]) +m4_set_add([a], [1], [added], [dup]) +m4_set_contains([a], [1], [yes], [no]) +m4_set_add([a], [1], [added], [dup]) +m4_set_contents([a]) +m4_set_remove([a], [1], [removed], [missing]) +m4_set_contains([a], [1], [yes], [no]) +m4_set_remove([a], [1], [removed], [missing]) +m4_set_add([a], [2], [added], [dup]) +m4_set_empty([a], [yes], [no]) +m4_set_delete([a]) +m4_set_empty([a], [yes], [no]) +m4_set_add_all([c], [1], [2], [3]) +m4_set_add_all([a]m4_set_listc([c])) +m4_set_contents([c], [-]) +m4_set_dump([a], [-]) +m4_set_contents([a]) +m4_set_add_all([a], [1], [2], [3])m4_set_add_all([b], [3], [], [4]) +m4_set_difference([a], [b]) +m4_set_difference([b], [a]) +m4_set_intersection([a], [b]) +m4_set_union([a], [b]) +m4_define([printodd], [m4_if(m4_eval([$1 & 1]), [1], [:$1])])dnl +m4_set_map([a], [printodd]) +m4_set_foreach([a], [i], [m4_if(m4_eval(i & 1), [1], [m4_set_remove([a], i)])]) +m4_set_list([a]) +m4_set_add([a], []) +m4_set_list([a]) +m4_set_remove([a], [2]) +m4_dquote(m4_set_list([a])) +m4_set_listc([a]) +m4_set_size([a]) +m4_set_delete([a]) +m4_dquote(m4_set_list([a])) +m4_indir([m4_dquote]m4_set_listc([a])) +m4_set_listc([a]) +m4_set_size([a]) +]], [[no +added +yes +dup +1 +removed +no +missing +added +no + +yes + + +1-2-3 +3-2-1 + + +,1,2 +,,4 +,3 +,1,2,3,,4 +:1:3 + +2 + +2, + +[] +, +1 + +[] + + +0 +]]) + +# Stress tests - check for unusual names/values +AT_CHECK_M4SUGAR_TEXT([[m4_define([a], [oops])dnl +m4_set_add([a], [a])dnl +m4_set_remove([a], [oops], [yes], [no]) +m4_set_add([a,b], [c])dnl +m4_set_add([a,b], [$*[]])dnl +m4_set_add_all([a], [b,c])dnl +m4_set_size([a]) +m4_count(m4_set_contents([a], [,])) +m4_count(m4_set_list([a], [,])) +m4_set_dump([a], [,]) +m4_set_contents([a,b], [,]) +m4_set_list([a,b]) +m4_set_foreach([$*[]], [$*[]], [oops]) +m4_set_add([$*[]], [])dnl +m4_set_remove([$*[]], [a], [yes], [no]) +m4_set_add([$*[]], [a])dnl +m4_set_foreach([$*[]], [$*[]], [-m4_defn([$*[]])m4_indir([$*[]])-]) +m4_set_remove([$*[]], [], [yes], [no]) +m4_set_add([c], [,])dnl +m4_set_foreach([a,b], [set], [:m4_set_listc(_m4_defn([set])):]) +]],[[no +2 +1 +2 +b,c,a +c,$*[] +c,$*[] + +no +---aoops- +yes +:,,::,a: +]]) + +# Stress tests - check for linear scaling (won't necessarily fail if +# quadratic, but hopefully users will complain if it appears to hang) +AT_CHECK_M4SUGAR_TEXT([[dnl +m4_for([i], [1], [10000], [], [m4_set_add([a], i)])dnl +m4_set_add_all([b]m4_for([i], [1], [10000], [], [,i]))dnl +m4_set_remove([a], [1])dnl +m4_set_remove([b], [10000])dnl +m4_set_add_all([a]m4_for([i], [1], [10000], [], [,i]))dnl +m4_for([i], [1], [10000], [], [m4_set_add([b], i)])dnl +m4_len(m4_set_contents([a])) +m4_len(m4_set_foreach([b], [b], [m4_if(m4_eval(b & 1), [1], + [m4_set_remove([b], b, [-])])])) +m4_set_size([b]) +m4_define([prune3x], [m4_if(m4_eval([$1 % 3]), [0], + [m4_set_remove([a], [$1], [-])])])dnl +m4_len(m4_set_map([a], [prune3x])) +m4_count(m4_shift(m4_set_intersection([a], [b]))) +]], [[38894 +5000 +5000 +3333 +3334 +]]) + +AT_CLEANUP + + +## ---------------------- ## +## __file__ and __line__. ## +## ---------------------- ## + +AT_SETUP([[__file__ and __line__]]) + +# Check that __file__ and __line__ work. +# Check that m4__file__ and m4__line__ are not defined +# (and get them to pass by the undefined-macro check). +# Try to not assume too much about AT_CHECK_M4SUGAR_TEXT. +AT_CHECK_M4SUGAR_TEXT([[dnl +m4_pattern_allow([m4__file__])dnl +m4_pattern_allow([m4__line__])dnl +m4__file__ +m4__line__ +__file__ +m4_define([first], __line__)dnl +m4_define([second], __line__)dnl +m4_assert(first + 1 == second)dnl +]], [[m4@&t@__@&t@file__ +m4@&t@__@&t@line__ +script.4s +]]) + +AT_CLEANUP |