xref: /freebsd/contrib/bmake/unit-tests/varmod-match.mk (revision 1d3f2ddc32fc37e4835aa5a51eabc8696c1e8114)
1# $NetBSD: varmod-match.mk,v 1.8 2022/03/27 18:39:01 rillig Exp $
2#
3# Tests for the :M variable modifier, which filters words that match the
4# given pattern.
5#
6# See ApplyModifier_Match and ModifyWord_Match for the implementation.
7
8.MAKEFLAGS: -dc
9
10NUMBERS=	One Two Three Four five six seven
11
12# Only keep words that start with an uppercase letter.
13.if ${NUMBERS:M[A-Z]*} != "One Two Three Four"
14.  error
15.endif
16
17# Only keep words that start with a character other than an uppercase letter.
18.if ${NUMBERS:M[^A-Z]*} != "five six seven"
19.  error
20.endif
21
22# Only keep words that don't start with s and at the same time end with
23# either of [ex].
24#
25# This test case ensures that the negation from the first character class
26# does not propagate to the second character class.
27.if ${NUMBERS:M[^s]*[ex]} != "One Three five"
28.  error
29.endif
30
31# Before 2020-06-13, this expression took quite a long time in Str_Match,
32# calling itself 601080390 times for 16 asterisks.
33.if ${:U****************:M****************b}
34.endif
35
36# To match a dollar sign in a word, double it.
37#
38# This is different from the :S and :C variable modifiers, where a '$'
39# has to be escaped as '\$'.
40.if ${:Ua \$ sign:M*$$*} != "\$"
41.  error
42.endif
43
44# In the :M modifier, '\$' does not escape a dollar.  Instead it is
45# interpreted as a backslash followed by whatever expression the
46# '$' starts.
47#
48# This differs from the :S, :C and several other variable modifiers.
49${:U*}=		asterisk
50.if ${:Ua \$ sign any-asterisk:M*\$*} != "any-asterisk"
51.  error
52.endif
53
54# TODO: ${VAR:M(((}}}}
55# TODO: ${VAR:M{{{)))}
56# TODO: ${VAR:M${UNBALANCED}}
57# TODO: ${VAR:M${:U(((\}\}\}}}
58
59.MAKEFLAGS: -d0
60
61# Special characters:
62#	*	matches 0 or more arbitrary characters
63#	?	matches a single arbitrary character
64#	\	starts an escape sequence, only outside ranges
65#	[	starts a set for matching a single character
66#	]	ends a set for matching a single character
67#	-	in a set, forms a range of characters
68#	^	as the first character in a set, negates the set
69#	(	during parsing of the pattern, starts a nesting level
70#	)	during parsing of the pattern, ends a nesting level
71#	{	during parsing of the pattern, starts a nesting level
72#	}	during parsing of the pattern, ends a nesting level
73#	:	during parsing of the pattern, finishes the pattern
74#	$	during parsing of the pattern, starts a nested expression
75#	#	in a line except a shell command, starts a comment
76#
77# Pattern parts:
78#	*	matches 0 or more arbitrary characters
79#	?	matches exactly 1 arbitrary character
80#	\x	matches exactly the character 'x'
81#	[...]	matches exactly 1 character from the set
82#	[^...]	matches exactly 1 character outside the set
83#	[a-z]	matches exactly 1 character from the range 'a' to 'z'
84#
85
86#	[]	matches never
87.if ${ ab a[]b a[b a b :L:M[]} != ""
88.  error
89.endif
90
91#	a[]b	matches never
92.if ${ ab a[]b a[b a b [ ] :L:Ma[]b} != ""
93.  error
94.endif
95
96#	[^]	matches exactly 1 arbitrary character
97.if ${ ab a[]b a[b a b [ ] :L:M[^]} != "a b [ ]"
98.  error
99.endif
100
101#	a[^]b	matches 'a', then exactly 1 arbitrary character, then 'b'
102.if ${ ab a[]b a[b a b :L:Ma[^]b} != "a[b"
103.  error
104.endif
105
106#	[Nn0]	matches exactly 1 character from the set 'N', 'n', '0'
107.if ${ a b N n 0 Nn0 [ ] :L:M[Nn0]} != "N n 0"
108.  error
109.endif
110
111#	[a-c]	matches exactly 1 character from the range 'a' to 'c'
112.if ${ A B C a b c d [a-c] [a] :L:M[a-c]} != "a b c"
113.  error
114.endif
115
116#	[c-a]	matches the same as [a-c]
117.if ${ A B C a b c d [a-c] [a] :L:M[c-a]} != "a b c"
118.  error
119.endif
120
121#	[^a-c67]
122#		matches a single character, except for 'a', 'b', 'c', '6' or
123#		'7'
124.if ${ A B C a b c d 5 6 7 8 [a-c] [a] :L:M[^a-c67]} != "A B C d 5 8"
125.  error
126.endif
127
128#	:	terminates the pattern
129.if ${ A * :L:M:} != ""
130.  error
131.endif
132
133#	\:	matches a colon
134.if ${ ${:U\: \:\:} :L:M\:} != ":"
135.  error
136.endif
137
138#	${:U\:}	matches a colon
139.if ${ ${:U\:} ${:U\:\:} :L:M${:U\:}} != ":"
140.  error
141.endif
142
143#	[:]	matches never since the ':' starts the next modifier
144# expect+2: Unknown modifier "]"
145# expect+1: Malformed conditional (${ ${:U\:} ${:U\:\:} :L:M[:]} != ":")
146.if ${ ${:U\:} ${:U\:\:} :L:M[:]} != ":"
147.  error
148.else
149.  error
150.endif
151
152#	[\]	matches exactly a backslash; no escaping takes place in
153#		character ranges
154# Without the 'a' in the below expressions, the backslash would end a word and
155# thus influence how the string is split into words.
156.if ${ ${:U\\a} ${:U\\\\a} :L:M[\]a} != "\\a"
157.  error
158.endif
159
160#.MAKEFLAGS: -dcv
161#
162# Incomplete patterns:
163#	[	matches TODO
164#	[x	matches TODO
165#	[^	matches TODO
166#	[-	matches TODO
167#	[xy	matches TODO
168#	[^x	matches TODO
169#	[\	matches TODO
170#
171#	[x-	matches exactly 'x', doesn't match 'x-'
172#	[^x-	matches TODO
173#	\	matches never
174
175
176# The modifier ':tW' prevents splitting at whitespace.  Even leading and
177# trailing whitespace is preserved.
178.if ${   plain   string   :L:tW:M*} != "   plain   string   "
179.  error
180.endif
181
182# Without the modifier ':tW', the string is split into words.  All whitespace
183# around and between the words is normalized to a single space.
184.if ${   plain    string   :L:M*} != "plain string"
185.  error
186.endif
187