diff options
Diffstat (limited to 'unit-tests')
-rw-r--r-- | unit-tests/Makefile (renamed from unit-tests/Makefile.in) | 19 | ||||
-rw-r--r-- | unit-tests/Makefile.config.in | 4 | ||||
-rw-r--r-- | unit-tests/cond-late.exp | 3 | ||||
-rw-r--r-- | unit-tests/cond-late.mk | 23 | ||||
-rw-r--r-- | unit-tests/dollar.exp | 51 | ||||
-rw-r--r-- | unit-tests/dollar.mk | 81 | ||||
-rw-r--r-- | unit-tests/escape.mk | 6 | ||||
-rw-r--r-- | unit-tests/forloop.exp | 3 | ||||
-rw-r--r-- | unit-tests/forloop.mk | 12 | ||||
-rw-r--r-- | unit-tests/include-main.exp | 6 | ||||
-rw-r--r-- | unit-tests/include-main.mk | 30 | ||||
-rw-r--r-- | unit-tests/include-sub.mk | 17 | ||||
-rw-r--r-- | unit-tests/include-subsub.mk | 7 | ||||
-rw-r--r-- | unit-tests/modorder.mk | 7 | ||||
-rw-r--r-- | unit-tests/sysv.exp | 8 | ||||
-rw-r--r-- | unit-tests/sysv.mk | 21 | ||||
-rw-r--r-- | unit-tests/varmod-edge.exp | 17 | ||||
-rw-r--r-- | unit-tests/varmod-edge.mk | 162 |
18 files changed, 458 insertions, 19 deletions
diff --git a/unit-tests/Makefile.in b/unit-tests/Makefile index e51d25455a50..5cf0212ce596 100644 --- a/unit-tests/Makefile.in +++ b/unit-tests/Makefile @@ -1,6 +1,6 @@ -# $Id: Makefile.in,v 1.49 2018/09/21 21:39:05 sjg Exp $ +# $Id: Makefile,v 1.54 2020/05/17 17:26:14 sjg Exp $ # -# $NetBSD: Makefile,v 1.53 2018/05/24 00:25:44 christos Exp $ +# $NetBSD: Makefile,v 1.58 2020/05/17 12:36:26 rillig Exp $ # # Unit tests for make(1) # The main targets are: @@ -15,28 +15,31 @@ # and it should be added to the TESTNAMES list. # -srcdir= @srcdir@ - .MAIN: all -UNIT_TESTS:= ${srcdir} +.-include "Makefile.config" + +UNIT_TESTS:= ${.PARSEDIR} .PATH: ${UNIT_TESTS} # Each test is in a sub-makefile. # Keep the list sorted. TESTNAMES= \ comment \ + cond-late \ cond1 \ cond2 \ + dollar \ + doterror \ + dotwait \ error \ export \ export-all \ export-env \ - doterror \ - dotwait \ forloop \ forsubst \ hash \ + include-main \ misc \ moderrs \ modmatch \ @@ -54,6 +57,7 @@ TESTNAMES= \ unexport-env \ varcmd \ varmisc \ + varmod-edge \ varquote \ varshell @@ -88,7 +92,6 @@ TEST_MAKE?= ${.MAKE} TOOL_SED?= sed TOOL_TR?= tr TOOL_DIFF?= diff -DIFF_FLAGS?= @diff_u@ .if defined(.PARSEDIR) # ensure consistent results from sort(1) diff --git a/unit-tests/Makefile.config.in b/unit-tests/Makefile.config.in new file mode 100644 index 000000000000..0fe24f08d2f9 --- /dev/null +++ b/unit-tests/Makefile.config.in @@ -0,0 +1,4 @@ +# $Id: Makefile.config.in,v 1.1 2018/12/30 17:14:24 sjg Exp $ + +srcdir= @srcdir@ +DIFF_FLAGS?= @diff_u@ diff --git a/unit-tests/cond-late.exp b/unit-tests/cond-late.exp new file mode 100644 index 000000000000..3717b088c646 --- /dev/null +++ b/unit-tests/cond-late.exp @@ -0,0 +1,3 @@ +yes +no +exit status 0 diff --git a/unit-tests/cond-late.mk b/unit-tests/cond-late.mk new file mode 100644 index 000000000000..2eb02b42b920 --- /dev/null +++ b/unit-tests/cond-late.mk @@ -0,0 +1,23 @@ +# $NetBSD: cond-late.mk,v 1.1 2020/04/29 23:15:21 rillig Exp $ +# +# Using the :? modifier, variable expressions can contain conditional +# expressions that are evaluated late. Any variables appearing in these +# conditions are expanded before parsing the condition. This is +# different from many other places. +# +# Because of this, variables that are used in these lazy conditions +# should not contain double-quotes, or the parser will probably fail. +# +# They should also not contain operators like == or <, since these are +# actually interpreted as these operators. This is demonstrated below. +# +# If the order of evaluation were to change to first parse the condition +# and then expand the variables, the output would change from the +# current "yes no" to "yes yes", since both variables are non-empty. + +COND.true= "yes" == "yes" +COND.false= "yes" != "yes" + +all: + @echo ${ ${COND.true} :?yes:no} + @echo ${ ${COND.false} :?yes:no} diff --git a/unit-tests/dollar.exp b/unit-tests/dollar.exp new file mode 100644 index 000000000000..496adc02f157 --- /dev/null +++ b/unit-tests/dollar.exp @@ -0,0 +1,51 @@ + +Printing dollar from literals and variables + +To survive the parser, a dollar character must be doubled. + 1 dollar literal => <single-quote-var-value> + 1 dollar literal eol => <> + 2 dollar literal => <$> + 4 dollar literal => <$$> +Some hungry part of make eats all the dollars after a :U modifier. + 1 dollar default => <> + 2 dollar default => <> + 4 dollar default => <> +This works as expected. + 1 dollar variable => <> + 2 dollar variable => <$> + 4 dollar variable => <$$> +Some hungry part of make eats all the dollars after a :U modifier. + 1 dollar var-default => <> + 2 dollar var-default => <$> + 4 dollar var-default => <$$> + +Dollar in :S pattern + + S,$,word, => <$XYword> + S,$X,word, => <$XY> + S,$$X,word, => <$XY> + S,$$$X,word, => <$XY> + S,$X,replaced, => <replaced> + S,$$X,replaced, => <replaced> + S,$$$X,replaced, => <replaced> + +Dollar in :C character class + +The A is replaced because the $$ is reduced to a single $, +which is then resolved to the variable X with the value VAR_X. +The effective character class becomes [VAR_XY]. + C,[$$XY],<&>,g => <$<A><X><Y>> + +Dollar in :C pattern + +For some reason, multiple dollars are folded into one. + C,$,dollar,g => <> + C,$$,dollar,g => <> + +Dollar in :S replacement + +For some reason, multiple dollars are folded into one. + S,word,a$Xo, => <aVAR_Xo> + S,word,a$$Xo, => <aVAR_Xo> + S,word,a$$$Xo, => <aVAR_Xo> +exit status 0 diff --git a/unit-tests/dollar.mk b/unit-tests/dollar.mk new file mode 100644 index 000000000000..b7f7d9fa7c9e --- /dev/null +++ b/unit-tests/dollar.mk @@ -0,0 +1,81 @@ +# $NetBSD: dollar.mk,v 1.3 2020/05/17 09:37:48 rillig Exp $ +# +# Test the various places where a dollar character can appear and +# see what happens. There are lots of surprises here. +# + +LIST= plain 'single' "double" 'mix'"ed" back\ slashed +WORD= word + +DOLLAR1= $ +DOLLAR2= $$ +DOLLAR4= $$$$ + +X= VAR_X +DOLLAR_XY= $$XY +DOLLAR_AXY= $$AXY + +H= @header() { printf '\n%s\n\n' "$$*"; }; header +T= @testcase() { printf '%23s => <%s>\n' "$$@"; }; testcase +C= @comment() { printf '%s\n' "$$*"; }; comment + +# These variable values are not accessed. +# The trailing dollar in the '1 dollar literal eol' test case accesses +# the empty variable instead, which is always guaranteed to be empty. +${:U }= space-var-value +${:U${.newline}}= newline-var-value +# But this one is accessed. +${:U'}= single-quote-var-value' + +all: + $H 'Printing dollar from literals and variables' + + $C 'To survive the parser, a dollar character must be doubled.' + $T '1 dollar literal' '$' + $T '1 dollar literal eol' ''$ + $T '2 dollar literal' '$$' + $T '4 dollar literal' '$$$$' + + $C 'Some hungry part of make eats all the dollars after a :U modifier.' + $T '1 dollar default' ''${:U$:Q} + $T '2 dollar default' ''${:U$$:Q} + $T '4 dollar default' ''${:U$$$$:Q} + + $C 'This works as expected.' + $T '1 dollar variable' ''${DOLLAR1:Q} + $T '2 dollar variable' ''${DOLLAR2:Q} + $T '4 dollar variable' ''${DOLLAR4:Q} + + $C 'Some hungry part of make eats all the dollars after a :U modifier.' + $T '1 dollar var-default' ''${:U${DOLLAR1}:Q} + $T '2 dollar var-default' ''${:U${DOLLAR2}:Q} + $T '4 dollar var-default' ''${:U${DOLLAR4}:Q} + + $H 'Dollar in :S pattern' + + $T 'S,$$,word,' ''${DOLLAR_XY:S,$,word,:Q} + $T 'S,$$X,word,' ''${DOLLAR_XY:S,$X,word,:Q} + $T 'S,$$$$X,word,' ''${DOLLAR_XY:S,$$X,word,:Q} + $T 'S,$$$$$$X,word,' ''${DOLLAR_XY:S,$$$X,word,:Q} + + $T 'S,$$X,replaced,' ''${X:S,$X,replaced,:Q} + $T 'S,$$$$X,replaced,' ''${X:S,$$X,replaced,:Q} + $T 'S,$$$$$$X,replaced,' ''${X:S,$$$X,replaced,:Q} + + $H 'Dollar in :C character class' + + $C 'The A is replaced because the $$$$ is reduced to a single $$,' + $C 'which is then resolved to the variable X with the value VAR_X.' + $C 'The effective character class becomes [VAR_XY].' + $T 'C,[$$$$XY],<&>,g' ''${DOLLAR_AXY:C,[$$XY],<&>,g:Q} + + $H 'Dollar in :C pattern' + $C 'For some reason, multiple dollars are folded into one.' + $T 'C,$$,dollar,g' ''${DOLLAR:C,$,dollar,g:Q} + $T 'C,$$$$,dollar,g' ''${DOLLAR:C,$$,dollar,g:Q} + + $H 'Dollar in :S replacement' + $C 'For some reason, multiple dollars are folded into one.' + $T 'S,word,a$$Xo,' ''${WORD:S,word,a$Xo,:Q} + $T 'S,word,a$$$$Xo,' ''${WORD:S,word,a$$Xo,:Q} + $T 'S,word,a$$$$$$Xo,' ''${WORD:S,word,a$$$Xo,:Q} diff --git a/unit-tests/escape.mk b/unit-tests/escape.mk index bb37c9217f4c..be9c4dd60e3f 100644 --- a/unit-tests/escape.mk +++ b/unit-tests/escape.mk @@ -1,4 +1,4 @@ -# $Id: escape.mk,v 1.1.1.2 2014/11/06 01:40:37 sjg Exp $ +# $Id: escape.mk,v 1.1.1.3 2020/01/22 01:07:14 sjg Exp $ # # Test backslash escaping. @@ -35,8 +35,8 @@ # Also, our practice is that an even number of backslashes before a # newline in a variable assignment simply stores the backslashes as part # of the value, and treats the newline as though it was not escaped. -# Similarly, ann even number of backslashes before a newline in a -# command simply uses the backslashes as part of the command test, but +# Similarly, an even number of backslashes before a newline in a +# command simply uses the backslashes as part of the command, but # does not escape the newline. This is compatible with GNU make. all: .PHONY diff --git a/unit-tests/forloop.exp b/unit-tests/forloop.exp index df14b751224c..998456190737 100644 --- a/unit-tests/forloop.exp +++ b/unit-tests/forloop.exp @@ -7,12 +7,13 @@ x=-I"This or that" x=-Ithat x="-DTHIS=\"this and that\"" cfl=-I/this -I"This or that" -Ithat "-DTHIS=\"this and that\"" +newline-item=(a) a=one b="two and three" a=four b="five" a=ONE b="TWO AND THREE" a=FOUR b="FIVE" We expect an error next: -make: "forloop.mk" line 38: Wrong number of words (9) in .for substitution list with 2 vars +make: "forloop.mk" line 46: Wrong number of words (9) in .for substitution list with 2 vars make: Fatal errors encountered -- cannot continue make: stopped in unit-tests OK diff --git a/unit-tests/forloop.mk b/unit-tests/forloop.mk index 9aad7c6b998a..dd3f07ddb19a 100644 --- a/unit-tests/forloop.mk +++ b/unit-tests/forloop.mk @@ -1,4 +1,4 @@ -# $Id: forloop.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $ +# $Id: forloop.mk,v 1.1.1.2 2020/05/05 00:54:40 sjg Exp $ all: for-loop @@ -33,7 +33,15 @@ X!= echo 'cfl=${cfl}' >&2; echo .for a b in ${EMPTY} X!= echo 'a=$a b=$b' >&2; echo .endfor -.endif + +# Since at least 1993, iteration stops at the first newline. +# Back then, the .newline variable didn't exist, therefore it was unlikely +# that a newline ever occured. +.for var in a${.newline}b${.newline}c +X!= echo 'newline-item=('${var:Q}')' 1>&2; echo +.endfor + +.endif # for-fail .for a b in ${LIST} ${LIST:tu} ${XTRA_LIST} X!= echo 'a=$a b=$b' >&2; echo diff --git a/unit-tests/include-main.exp b/unit-tests/include-main.exp new file mode 100644 index 000000000000..7a55c6e97dce --- /dev/null +++ b/unit-tests/include-main.exp @@ -0,0 +1,6 @@ +main-before-ok +sub-before-ok +subsub-ok +sub-after-fail(include-sub.mk) +main-after-fail(include-sub.mk) +exit status 0 diff --git a/unit-tests/include-main.mk b/unit-tests/include-main.mk new file mode 100644 index 000000000000..452b6102a5ce --- /dev/null +++ b/unit-tests/include-main.mk @@ -0,0 +1,30 @@ +# $NetBSD: include-main.mk,v 1.1 2020/05/17 12:36:26 rillig Exp $ +# +# Demonstrates that the .INCLUDEDFROMFILE magic variable does not behave +# as described in the manual page. +# +# The manual page says that it is the "filename of the file this Makefile +# was included from", while in reality it is the "filename in which the +# latest .include happened". +# + +.if !defined(.INCLUDEDFROMFILE) +LOG+= main-before-ok +.else +. for f in ${.INCLUDEDFROMFILE} +LOG+= main-before-fail\(${f:Q}\) +. endfor +.endif + +.include "include-sub.mk" + +.if !defined(.INCLUDEDFROMFILE) +LOG+= main-after-ok +.else +. for f in ${.INCLUDEDFROMFILE} +LOG+= main-after-fail\(${f:Q}\) +. endfor +.endif + +all: + @printf '%s\n' ${LOG} diff --git a/unit-tests/include-sub.mk b/unit-tests/include-sub.mk new file mode 100644 index 000000000000..28856fcc6e60 --- /dev/null +++ b/unit-tests/include-sub.mk @@ -0,0 +1,17 @@ +# $NetBSD: include-sub.mk,v 1.1 2020/05/17 12:36:26 rillig Exp $ + +.if ${.INCLUDEDFROMFILE} == "include-main.mk" +LOG+= sub-before-ok +.else +LOG+= sub-before-fail +.endif + +.include "include-subsub.mk" + +.if ${.INCLUDEDFROMFILE} == "include-main.mk" +LOG+= sub-after-ok +.else +. for f in ${.INCLUDEDFROMFILE} +LOG+= sub-after-fail\(${f:Q}\) +. endfor +.endif diff --git a/unit-tests/include-subsub.mk b/unit-tests/include-subsub.mk new file mode 100644 index 000000000000..e8fa1186f41d --- /dev/null +++ b/unit-tests/include-subsub.mk @@ -0,0 +1,7 @@ +# $NetBSD: include-subsub.mk,v 1.1 2020/05/17 12:36:26 rillig Exp $ + +.if ${.INCLUDEDFROMFILE:T} == "include-sub.mk" +LOG+= subsub-ok +.else +LOG+= subsub-fail +.endif diff --git a/unit-tests/modorder.mk b/unit-tests/modorder.mk index bc24d339f45a..0f809391712f 100644 --- a/unit-tests/modorder.mk +++ b/unit-tests/modorder.mk @@ -1,4 +1,4 @@ -# $NetBSD: modorder.mk,v 1.1 2014/08/21 13:44:51 apb Exp $ +# $NetBSD: modorder.mk,v 1.2 2020/01/07 22:42:14 rillig Exp $ LIST= one two three four five six seven eight nine ten LISTX= ${LIST:Ox} @@ -12,8 +12,9 @@ all: @echo "LIST:O = ${LIST:O}" # Note that 1 in every 10! trials two independently generated # randomized orderings will be the same. The test framework doesn't - # support checking probabilistic output, so we accept that the test - # will incorrectly fail with probability 2.8E-7. + # support checking probabilistic output, so we accept that each of the + # 3 :Ox tests will incorrectly fail with probability 2.756E-7, which + # lets the whole test fail once in 1.209.600 runs, on average. @echo "LIST:Ox = `test '${LIST:Ox}' != '${LIST:Ox}' ${TEST_RESULT}`" @echo "LIST:O:Ox = `test '${LIST:O:Ox}' != '${LIST:O:Ox}' ${TEST_RESULT}`" @echo "LISTX = `test '${LISTX}' != '${LISTX}' ${TEST_RESULT}`" diff --git a/unit-tests/sysv.exp b/unit-tests/sysv.exp index 4cce2de31918..610f97c39e85 100644 --- a/unit-tests/sysv.exp +++ b/unit-tests/sysv.exp @@ -4,4 +4,12 @@ fun fun fun In the Sun +acme +aam.d +sam.c +a%.c +asam.c.c +asam.c +a.c.c + exit status 0 diff --git a/unit-tests/sysv.mk b/unit-tests/sysv.mk index d5e99ff950ae..2bd128eb7130 100644 --- a/unit-tests/sysv.mk +++ b/unit-tests/sysv.mk @@ -1,4 +1,4 @@ -# $Id: sysv.mk,v 1.2 2014/08/30 22:25:14 sjg Exp $ +# $Id: sysv.mk,v 1.4 2020/05/07 01:17:51 sjg Exp $ FOO ?= FOOBAR = ${FOO:=bar} @@ -11,7 +11,7 @@ FUN = ${B}${S}fun SUN = the Sun # we expect nothing when FOO is empty -all: foo fun +all: foo fun sam bla foo: @echo FOOBAR = ${FOOBAR} @@ -24,3 +24,20 @@ fun: @echo ${FUN:${B}${S}fun=fun} @echo ${FUN:${B}${S}%=%} @echo ${In:L:%=% ${SUN}} + + +SAM=sam.c + +sam: + @echo ${SAM:s%.c=acme} + @echo ${SAM:s%.c=a%.d} + @echo ${SAM:s.c=a%.d} + @echo ${SAM:sam.c=a%.c} + @echo ${SAM:%=a%.c} + @echo ${SAM:%.c=a%.c} + @echo ${SAM:sam%=a%.c} + +BLA= + +bla: + @echo $(BLA:%=foo/%x) diff --git a/unit-tests/varmod-edge.exp b/unit-tests/varmod-edge.exp new file mode 100644 index 000000000000..b3b2e3a92f95 --- /dev/null +++ b/unit-tests/varmod-edge.exp @@ -0,0 +1,17 @@ +make: Unclosed variable specification (expecting '}') for "" (value "*)") modifier U +make: Unclosed substitution for INP.eq-esc (= missing) +ok M-paren +ok M-mixed +ok M-unescape +ok M-nest-mix +ok M-nest-brk +ok M-pat-err +ok M-bsbs +ok M-bs1-par +ok M-bs2-par +ok M-128 +ok eq-ext +ok eq-q +ok eq-bs +ok eq-esc +exit status 0 diff --git a/unit-tests/varmod-edge.mk b/unit-tests/varmod-edge.mk new file mode 100644 index 000000000000..561eb6116891 --- /dev/null +++ b/unit-tests/varmod-edge.mk @@ -0,0 +1,162 @@ +# $NetBSD: varmod-edge.mk,v 1.7 2020/04/27 14:07:22 christos Exp $ +# +# Tests for edge cases in variable modifiers. +# +# These tests demonstrate the current implementation in small examples. +# They may contain surprising behavior. +# +# Each test consists of: +# - INP, the input to the test +# - MOD, the expression for testing the modifier +# - EXP, the expected output + +TESTS+= M-paren +INP.M-paren= (parentheses) {braces} (opening closing) () +MOD.M-paren= ${INP.M-paren:M(*)} +EXP.M-paren= (parentheses) () + +# The first closing brace matches the opening parenthesis. +# The second closing brace actually ends the variable expression. +# +# XXX: This is unexpected but rarely occurs in practice. +TESTS+= M-mixed +INP.M-mixed= (paren-brace} ( +MOD.M-mixed= ${INP.M-mixed:M(*}} +EXP.M-mixed= (paren-brace} + +# After the :M modifier has parsed the pattern, only the closing brace +# and the colon are unescaped. The other characters are left as-is. +# To actually see this effect, the backslashes in the :M modifier need +# to be doubled since single backslashes would simply be unescaped by +# Str_Match. +# +# XXX: This is unexpected. The opening brace should also be unescaped. +TESTS+= M-unescape +INP.M-unescape= ({}): \(\{\}\)\: \(\{}\): +MOD.M-unescape= ${INP.M-unescape:M\\(\\{\\}\\)\\:} +EXP.M-unescape= \(\{}\): + +# When the :M and :N modifiers are parsed, the pattern finishes as soon +# as open_parens + open_braces == closing_parens + closing_braces. This +# means that ( and } form a matching pair. +# +# Nested variable expressions are not parsed as such. Instead, only the +# parentheses and braces are counted. This leads to a parse error since +# the nested expression is not "${:U*)}" but only "${:U*)", which is +# missing the closing brace. The expression is evaluated anyway. +# The final brace in the output comes from the end of M.nest-mix. +# +# XXX: This is unexpected but rarely occurs in practice. +TESTS+= M-nest-mix +INP.M-nest-mix= (parentheses) +MOD.M-nest-mix= ${INP.M-nest-mix:M${:U*)}} +EXP.M-nest-mix= (parentheses)} +# make: Unclosed variable specification (expecting '}') for "" (value "*)") modifier U + +# In contrast to parentheses and braces, the brackets are not counted +# when the :M modifier is parsed since Makefile variables only take the +# ${VAR} or $(VAR) forms, but not $[VAR]. +# +# The final ] in the pattern is needed to close the character class. +TESTS+= M-nest-brk +INP.M-nest-brk= [ [[ [[[ +MOD.M-nest-brk= ${INP.M-nest-brk:M${:U[[[[[]}} +EXP.M-nest-brk= [ + +# The pattern in the nested variable has an unclosed character class. +# No error is reported though, and the pattern is closed implicitly. +# +# XXX: It is unexpected that no error is reported. +# See str.c, function Str_Match. +# +# Before 2019-12-02, this test case triggered an out-of-bounds read +# in Str_Match. +TESTS+= M-pat-err +INP.M-pat-err= [ [[ [[[ +MOD.M-pat-err= ${INP.M-pat-err:M${:U[[}} +EXP.M-pat-err= [ + +# The first backslash does not escape the second backslash. +# Therefore, the second backslash escapes the parenthesis. +# This means that the pattern ends there. +# The final } in the output comes from the end of MOD.M-bsbs. +# +# If the first backslash were to escape the second backslash, the first +# closing brace would match the opening parenthesis (see M-mixed), and +# the second closing brace would be needed to close the variable. +# After that, the remaining backslash would escape the parenthesis in +# the pattern, therefore (} would match. +TESTS+= M-bsbs +INP.M-bsbs= (} \( \(} +MOD.M-bsbs= ${INP.M-bsbs:M\\(}} +EXP.M-bsbs= \(} +#EXP.M-bsbs= (} # If the first backslash were to escape ... + +# The backslash in \( does not escape the parenthesis, therefore it +# counts for the nesting level and matches with the first closing brace. +# The second closing brace closes the variable, and the third is copied +# literally. +# +# The second :M in the pattern is nested between ( and }, therefore it +# does not start a new modifier. +TESTS+= M-bs1-par +INP.M-bs1-par= ( (:M (:M} \( \(:M \(:M} +MOD.M-bs1-par= ${INP.M-bs1-par:M\(:M*}}} +EXP.M-bs1-par= (:M}} + +# The double backslash is passed verbatim to the pattern matcher. +# The Str_Match pattern is \\(:M*}, and there the backslash is unescaped. +# Again, the ( takes place in the nesting level, and there is no way to +# prevent this, no matter how many backslashes are used. +TESTS+= M-bs2-par +INP.M-bs2-par= ( (:M (:M} \( \(:M \(:M} +MOD.M-bs2-par= ${INP.M-bs2-par:M\\(:M*}}} +EXP.M-bs2-par= \(:M}} + +# Str_Match uses a recursive algorithm for matching the * patterns. +# Make sure that it survives patterns with 128 asterisks. +# That should be enough for all practical purposes. +# To produce a stack overflow, just add more :Qs below. +TESTS+= M-128 +INP.M-128= ${:U\\:Q:Q:Q:Q:Q:Q:Q:S,\\,x,g} +PAT.M-128= ${:U\\:Q:Q:Q:Q:Q:Q:Q:S,\\,*,g} +MOD.M-128= ${INP.M-128:M${PAT.M-128}} +EXP.M-128= ${INP.M-128} + +# This is the normal SysV substitution. Nothing surprising here. +TESTS+= eq-ext +INP.eq-ext= file.c file.cc +MOD.eq-ext= ${INP.eq-ext:%.c=%.o} +EXP.eq-ext= file.o file.cc + +# The SysV := modifier is greedy and consumes all the modifier text +# up until the closing brace or parenthesis. The :Q may look like a +# modifier, but it really isn't, that's why it appears in the output. +TESTS+= eq-q +INP.eq-q= file.c file.cc +MOD.eq-q= ${INP.eq-q:%.c=%.o:Q} +EXP.eq-q= file.o:Q file.cc + +# The = in the := modifier can be escaped. +TESTS+= eq-bs +INP.eq-bs= file.c file.c=%.o +MOD.eq-bs= ${INP.eq-bs:%.c\=%.o=%.ext} +EXP.eq-bs= file.c file.ext + +# Having only an escaped = results in a parse error. +# The call to "pattern.lhs = VarGetPattern" fails. +TESTS+= eq-esc +INP.eq-esc= file.c file... +MOD.eq-esc= ${INP.eq-esc:a\=b} +EXP.eq-esc= # empty +# make: Unclosed substitution for INP.eq-esc (= missing) + +all: +.for test in ${TESTS} +. if ${MOD.${test}} == ${EXP.${test}} + @printf 'ok %s\n' ${test:Q}'' +. else + @printf 'error in %s: expected %s, got %s\n' \ + ${test:Q}'' ${EXP.${test}:Q}'' ${MOD.${test}:Q}'' +. endif +.endfor |