xref: /freebsd/contrib/bmake/unit-tests/varmod-to-separator.mk (revision a64729f5077d77e13b9497cb33ecb3c82e606ee8)
1# $NetBSD: varmod-to-separator.mk,v 1.18 2024/07/05 19:47:22 rillig Exp $
2#
3# Tests for the :ts variable modifier, which joins the words of the variable
4# using an arbitrary character as word separator.
5
6WORDS=	one two three four five six
7
8# The words are separated by a single space, just as usual.
9.if ${WORDS:ts } != "one two three four five six"
10.  warning Space as separator does not work.
11.endif
12
13# The separator can be an arbitrary character, for example a comma.
14.if ${WORDS:ts,} != "one,two,three,four,five,six"
15.  warning Comma as separator does not work.
16.endif
17
18# After the :ts modifier, other modifiers can follow.
19.if ${WORDS:ts/:tu} != "ONE/TWO/THREE/FOUR/FIVE/SIX"
20.  warning Chaining modifiers does not work.
21.endif
22
23# To use the ':' as the separator, just write it normally.
24# The first colon is the separator, the second ends the modifier.
25.if ${WORDS:ts::tu} != "ONE:TWO:THREE:FOUR:FIVE:SIX"
26.  warning Colon as separator does not work.
27.endif
28
29# When there is just a colon but no other character, the words are
30# "separated" by an empty string, that is, they are all squashed
31# together.
32.if ${WORDS:ts:tu} != "ONETWOTHREEFOURFIVESIX"
33.  warning Colon as separator does not work.
34.endif
35
36# Applying the :tu modifier first and then the :ts modifier does not change
37# anything since neither of these modifiers is related to how the string is
38# split into words.  Beware of separating the words using a single or double
39# quote though, or other special characters like dollar or backslash.
40#
41# This example also demonstrates that the closing brace is not interpreted
42# as a separator, but as the closing delimiter of the whole
43# expression.
44.if ${WORDS:tu:ts} != "ONETWOTHREEFOURFIVESIX"
45.  warning Colon as separator does not work.
46.endif
47
48# The '}' plays the same role as the ':' in the preceding examples.
49# Since there is a single character before it, that character is taken as
50# the separator.
51.if ${WORDS:tu:ts/} != "ONE/TWO/THREE/FOUR/FIVE/SIX"
52.  warning Colon as separator does not work.
53.endif
54
55# Now it gets interesting and ambiguous:  The separator could either be empty
56# since it is followed by a colon.  Or it could be the colon since that
57# colon is followed by the closing brace.  It's the latter case.
58.if ${WORDS:ts:} != "one:two:three:four:five:six"
59.  warning Colon followed by closing brace does not work.
60.endif
61
62# As in the ${WORDS:tu:ts} example above, the separator is empty.
63.if ${WORDS:ts} != "onetwothreefourfivesix"
64.  warning Empty separator before closing brace does not work.
65.endif
66
67# The :ts modifier can be followed by other modifiers.
68.if ${WORDS:ts:S/two/2/} != "one2threefourfivesix"
69.  warning Separator followed by :S modifier does not work.
70.endif
71
72# The :ts modifier can follow other modifiers.
73.if ${WORDS:S/two/2/:ts} != "one2threefourfivesix"
74.  warning :S modifier followed by :ts modifier does not work.
75.endif
76
77# The :ts modifier with an actual separator can be followed by other
78# modifiers.
79.if ${WORDS:ts/:S/two/2/} != "one/2/three/four/five/six"
80.  warning The :ts modifier followed by an :S modifier does not work.
81.endif
82
83# After the modifier ':ts/', the expression value is a single word since all
84# spaces have been replaced with '/'.  This single word does not start with
85# 'two', which makes the modifier ':S' a no-op.
86.if ${WORDS:ts/:S/^two/2/} != "one/two/three/four/five/six"
87.  error
88.endif
89
90# After the :ts modifier, the whole string is interpreted as a single
91# word since all spaces have been replaced with x.  Because of this single
92# word, only the first 'b' is replaced with 'B'.
93.if ${aa bb aa bb aa bb:L:tsx:S,b,B,} != "aaxBbxaaxbbxaaxbb"
94.  error
95.endif
96
97# The :ts modifier also applies to word separators that are added
98# afterwards.  First, the modifier ':tsx' joins the 3 words, then the modifier
99# ':S' replaces the 2 'b's with spaces.  These spaces are part of the word,
100# so when the words are joined at the end of the modifier ':S', there is only
101# a single word, and the custom separator from the modifier ':tsx' has no
102# effect.
103.if ${a ababa c:L:tsx:S,b, ,g} != "axa a axc"
104.  error
105.endif
106
107# Adding the modifier ':M*' at the end of the above chain splits the
108# expression value and then joins it again.  At this point of splitting, the
109# newly added spaces are treated as word separators, resulting in 3 words.
110# When these 3 words are joined, the separator from the modifier ':tsx' is
111# used.
112.if ${a ababa c:L:tsx:S,b, ,g:M*} != "axaxaxaxc"
113.  error
114.endif
115
116# Not all modifiers use the separator from the previous modifier ':ts' though.
117# The modifier ':@' always uses a space as word separator instead.  This has
118# probably been an oversight during implementation.  For consistency, the
119# result should rather be "axaxaxaxc", as in the previous example.
120.if ${a ababa c:L:tsx:S,b, ,g:@v@$v@} != "axa a axc"
121.  error
122.endif
123
124# Adding a final :M* modifier applies the :ts separator again, though.
125.if ${a ababa c:L:tsx:S,b, ,g:@v@${v}@:M*} != "axaxaxaxc"
126.  error
127.endif
128
129# The separator can be \n, which is a newline.
130.if ${WORDS:[1..3]:ts\n} != "one${.newline}two${.newline}three"
131.  warning The separator \n does not produce a newline.
132.endif
133
134# The separator can be \t, which is a tab.
135.if ${WORDS:[1..3]:ts\t} != "one	two	three"
136.  warning The separator \t does not produce a tab.
137.endif
138
139# The separator can be given as octal number.
140.if ${WORDS:[1..3]:ts\012:tu} != "ONE${.newline}TWO${.newline}THREE"
141.  warning The separator \012 is not interpreted in octal ASCII.
142.endif
143
144# The octal number can have as many digits as it wants.
145.if ${WORDS:[1..2]:ts\000000000000000000000000012:tu} != "ONE${.newline}TWO"
146.  warning The separator \012 cannot have many leading zeroes.
147.endif
148
149# The value of the separator character must not be outside the value space
150# for an unsigned character though.
151#
152# Since 2020-11-01, these out-of-bounds values are rejected.
153# expect+2: while evaluating variable "WORDS" with value "one two three": Invalid character number at "400:tu}"
154# expect+1: Malformed conditional (${WORDS:[1..3]:ts\400:tu})
155.if ${WORDS:[1..3]:ts\400:tu}
156.  warning The separator \400 is accepted even though it is out of bounds.
157.else
158.  warning The separator \400 is accepted even though it is out of bounds.
159.endif
160
161# The separator can be given as hexadecimal number.
162.if ${WORDS:[1..3]:ts\xa:tu} != "ONE${.newline}TWO${.newline}THREE"
163.  warning The separator \xa is not interpreted in hexadecimal ASCII.
164.endif
165
166# The hexadecimal number must be in the range of an unsigned char.
167#
168# Since 2020-11-01, these out-of-bounds values are rejected.
169# expect+2: while evaluating variable "WORDS" with value "one two three": Invalid character number at "100:tu}"
170# expect+1: Malformed conditional (${WORDS:[1..3]:ts\x100:tu})
171.if ${WORDS:[1..3]:ts\x100:tu}
172.  warning The separator \x100 is accepted even though it is out of bounds.
173.else
174.  warning The separator \x100 is accepted even though it is out of bounds.
175.endif
176
177# The number after ':ts\x' must be hexadecimal.
178# expect+2: while evaluating variable "word" with value "word": Invalid character number at ",}"
179# expect+1: Malformed conditional (${word:L:ts\x,})
180.if ${word:L:ts\x,}
181.endif
182
183# The hexadecimal number must be in the range of 'unsigned long' on all
184# supported platforms.
185# expect+2: while evaluating variable "word" with value "word": Invalid character number at "112233445566778899}"
186# expect+1: Malformed conditional (${word:L:ts\x112233445566778899})
187.if ${word:L:ts\x112233445566778899}
188.endif
189
190# Negative numbers are not allowed for the separator character.
191# expect+2: while evaluating variable "WORDS" with value "one two three": Bad modifier ":ts\-300"
192# expect+1: Malformed conditional (${WORDS:[1..3]:ts\-300:tu})
193.if ${WORDS:[1..3]:ts\-300:tu}
194.  warning The separator \-300 is accepted even though it is negative.
195.else
196.  warning The separator \-300 is accepted even though it is negative.
197.endif
198
199# The character number is interpreted as octal number by default.
200# The digit '8' is not an octal digit though.
201# expect+2: while evaluating variable "1 2 3" with value "1 2 3": Bad modifier ":ts\8"
202# expect+1: Malformed conditional (${1 2 3:L:ts\8:tu})
203.if ${1 2 3:L:ts\8:tu}
204.  warning The separator \8 is accepted even though it is not octal.
205.else
206.  warning The separator \8 is accepted even though it is not octal.
207.endif
208
209# Trailing characters after the octal character number are rejected.
210# expect+2: while evaluating variable "1 2 3" with value "1 2 3": Bad modifier ":ts\100L"
211# expect+1: Malformed conditional (${1 2 3:L:ts\100L})
212.if ${1 2 3:L:ts\100L}
213.  warning The separator \100L is accepted even though it contains an 'L'.
214.else
215.  warning The separator \100L is accepted even though it contains an 'L'.
216.endif
217
218# Trailing characters after the hexadecimal character number are rejected.
219# expect+2: while evaluating variable "1 2 3" with value "1 2 3": Bad modifier ":ts\x40g"
220# expect+1: Malformed conditional (${1 2 3:L:ts\x40g})
221.if ${1 2 3:L:ts\x40g}
222.  warning The separator \x40g is accepted even though it contains a 'g'.
223.else
224.  warning The separator \x40g is accepted even though it contains a 'g'.
225.endif
226
227
228# In the :t modifier, the :t must be followed by any of A, l, s, u.
229# expect+2: while evaluating variable "WORDS" with value "one two three four five six": Bad modifier ":tx"
230# expect+1: Malformed conditional (${WORDS:tx})
231.if ${WORDS:tx}
232.  error
233.else
234.  error
235.endif
236
237# The word separator can only be a single character.
238# expect+2: while evaluating variable "WORDS" with value "one two three four five six": Bad modifier ":ts\X"
239# expect+1: Malformed conditional (${WORDS:ts\X})
240.if ${WORDS:ts\X}
241.  error
242.else
243.  error
244.endif
245
246# After the backslash, only n, t, an octal number, or x and a hexadecimal
247# number are allowed.
248# expect+2: while evaluating variable "WORDS" with value "one two three four five six": Bad modifier ":t\X"
249# expect+1: Malformed conditional (${WORDS:t\X} != "anything")
250.if ${WORDS:t\X} != "anything"
251.  info This line is not reached.
252.endif
253
254
255# Since 2003.07.23.18.06.46 and before 2016.03.07.20.20.35, the modifier ':ts'
256# interpreted an "octal escape" as decimal if the first digit was not '0'.
257.if ${:Ua b:ts\61} != "a1b"	# decimal would have been "a=b"
258.  error
259.endif
260
261# Since the character escape is always interpreted as octal, let's see what
262# happens for non-octal digits.  From 2003.07.23.18.06.46 to
263# 2016.02.27.16.20.06, the result was '1E2', since 2016.03.07.20.20.35 make no
264# longer accepts this escape and complains.
265# expect+2: while evaluating "${:Ua b:ts\69}" with value "a b": Bad modifier ":ts\69"
266# expect+1: Malformed conditional (${:Ua b:ts\69})
267.if ${:Ua b:ts\69}
268.  error
269.else
270.  error
271.endif
272
273# Try whether bmake is Unicode-ready.
274# expect+2: while evaluating "${:Ua b:ts\x1F60E}" with value "a b": Invalid character number at "1F60E}"
275# expect+1: Malformed conditional (${:Ua b:ts\x1F60E})
276.if ${:Ua b:ts\x1F60E}		# U+1F60E "smiling face with sunglasses"
277.  error
278.else
279.  error
280.endif
281