xref: /freebsd/contrib/bmake/unit-tests/varmod-to-separator.mk (revision 759b177aecbfc49ebc900739954ac56b1aa5fc53)
1# $NetBSD: varmod-to-separator.mk,v 1.23 2025/03/30 00:35:52 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.  error
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.  error
16.endif
17
18# After the :ts modifier, other modifiers can follow.
19.if ${WORDS:ts/:tu} != "ONE/TWO/THREE/FOUR/FIVE/SIX"
20.  error
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.  error
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.  error
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.  error
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.  error
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.  error
60.endif
61
62# As in the ${WORDS:tu:ts} example above, the separator is empty.
63.if ${WORDS:ts} != "onetwothreefourfivesix"
64.  error
65.endif
66
67# The :ts modifier can be followed by other modifiers.
68.if ${WORDS:ts:S/two/2/} != "one2threefourfivesix"
69.  error
70.endif
71
72# The :ts modifier can follow other modifiers.
73.if ${WORDS:S/two/2/:ts} != "one2threefourfivesix"
74.  error
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.  error
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.  error
132.endif
133
134# The separator can be \t, which is a tab.
135.if ${WORDS:[1..3]:ts\t} != "one	two	three"
136.  error
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.  error
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.  error
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+1: Invalid character number at "400:tu}"
154.if ${WORDS:[1..3]:ts\400:tu}
155.  error
156.else
157.  error
158.endif
159
160# The separator can be given as hexadecimal number.
161.if ${WORDS:[1..3]:ts\xa:tu} != "ONE${.newline}TWO${.newline}THREE"
162.  error
163.endif
164
165# The hexadecimal number must be in the range of an unsigned char.
166#
167# Since 2020-11-01, these out-of-bounds values are rejected.
168# expect+1: Invalid character number at "100:tu}"
169.if ${WORDS:[1..3]:ts\x100:tu}
170.  error
171.else
172.  error
173.endif
174
175# The number after ':ts\x' must be hexadecimal.
176# expect+1: Invalid character number at ",}"
177.if ${word:L:ts\x,}
178.endif
179
180# The hexadecimal number must be in the range of 'unsigned long' on all
181# supported platforms.
182# expect+1: Invalid character number at "112233445566778899}"
183.if ${word:L:ts\x112233445566778899}
184.endif
185
186# Negative numbers are not allowed for the separator character.
187# expect+1: Unknown modifier ":ts\-300"
188.if ${WORDS:[1..3]:ts\-300:tu}
189.  error
190.else
191.  error
192.endif
193
194# The character number is interpreted as octal number by default.
195# The digit '8' is not an octal digit though.
196# expect+1: Unknown modifier ":ts\8"
197.if ${1 2 3:L:ts\8:tu}
198.  error
199.else
200.  error
201.endif
202
203# Trailing characters after the octal character number are rejected.
204# expect+1: Unknown modifier ":ts\100L"
205.if ${1 2 3:L:ts\100L}
206.  error
207.else
208.  error
209.endif
210
211# Trailing characters after the hexadecimal character number are rejected.
212# expect+1: Unknown modifier ":ts\x40g"
213.if ${1 2 3:L:ts\x40g}
214.  error
215.else
216.  error
217.endif
218
219
220# In the :t modifier, the :t must be followed by any of A, l, s, u.
221# expect+1: Unknown modifier ":tx"
222.if ${WORDS:tx}
223.  error
224.else
225.  error
226.endif
227
228# The word separator can only be a single character.
229# expect+1: Unknown modifier ":ts\X"
230.if ${WORDS:ts\X}
231.  error
232.else
233.  error
234.endif
235
236# After the backslash, only n, t, an octal number, or x and a hexadecimal
237# number are allowed.
238# expect+1: Unknown modifier ":ts\X"
239.if ${WORDS:ts\X} != "anything"
240.  error
241.endif
242
243
244# Since 2003.07.23.18.06.46 and before 2016.03.07.20.20.35, the modifier ':ts'
245# interpreted an "octal escape" as decimal if the first digit was not '0'.
246.if ${:Ua b:ts\61} != "a1b"	# decimal would have been "a=b"
247.  error
248.endif
249
250# Since the character escape is always interpreted as octal, let's see what
251# happens for non-octal digits.  From 2003.07.23.18.06.46 to
252# 2016.02.27.16.20.06, the result was '1E2', since 2016.03.07.20.20.35 make no
253# longer accepts this escape and complains.
254# expect+1: Unknown modifier ":ts\69"
255.if ${:Ua b:ts\69}
256.  error
257.else
258.  error
259.endif
260
261# Try whether bmake is Unicode-ready.
262# expect+1: Invalid character number at "1F60E}"
263.if ${:Ua b:ts\x1F60E}		# U+1F60E "smiling face with sunglasses"
264.  error
265.else
266.  error
267.endif
268