xref: /freebsd/contrib/bmake/unit-tests/cond-func-empty.mk (revision 9f23cbd6cae82fd77edfad7173432fa8dccd0a95)
1# $NetBSD: cond-func-empty.mk,v 1.20 2023/06/01 20:56:35 rillig Exp $
2#
3# Tests for the empty() function in .if conditions, which tests a variable
4# expression for emptiness.
5#
6# Note that the argument in the parentheses is a variable name, not a variable
7# expression, optionally followed by variable modifiers.
8#
9
10.undef UNDEF
11EMPTY=	# empty
12SPACE=	${:U }
13WORD=	word
14
15# An undefined variable is empty.
16.if !empty(UNDEF)
17.  error
18.endif
19
20# An undefined variable has the empty string as the value, and the :M
21# variable modifier does not change that.
22#
23.if !empty(UNDEF:M*)
24.  error
25.endif
26
27# The :S modifier replaces the empty value with an actual word.  After
28# applying the :S modifier to the expression, its value is 'empty', so it is
29# no longer empty, but it is still based on an undefined variable.  There are
30# a few modifiers that turn an undefined expression into a defined expression,
31# among them :U and :D, but not :S.  Therefore, at the end of evaluating the
32# expression, the expression is still undefined, so its final value becomes an
33# empty string.
34#
35# XXX: This is hard to explain to someone who doesn't know these
36# implementation details.
37#
38.if !empty(UNDEF:S,^$,value,W)
39.  error
40.endif
41
42# The :U modifier changes the state of a previously undefined expression from
43# DEF_UNDEF to DEF_DEFINED.  This marks the expression as "being interesting
44# enough to be further processed".
45#
46.if empty(UNDEF:S,^$,value,W:Ufallback)
47.  error
48.endif
49
50# When an expression is based on an undefined variable, its modifiers interact
51# in sometimes surprising ways.  Applying the :S modifier to the undefined
52# expression makes its value non-empty, but doesn't change that the expression
53# is based on an undefined variable.  The :U modifier that follows only looks
54# at the definedness state to decide whether the variable is defined or not.
55# This kind of makes sense since the :U modifier tests the _variable_, not the
56# _expression_.
57#
58# Since the variable was undefined to begin with, the fallback value from the
59# :U modifier is used in this expression, instead of keeping the 'value' from
60# the :S modifier.
61#
62.if ${UNDEF:S,^$,value,W:Ufallback} != "fallback"
63.  error
64.endif
65
66# The variable EMPTY is completely empty (0 characters).
67.if !empty(EMPTY)
68.  error
69.endif
70
71# The variable SPACE has a single space, which counts as being empty.
72.if !empty(SPACE)
73.  error
74.endif
75
76# The variable .newline has a single newline, which counts as being empty.
77.if !empty(.newline)
78.  error
79.endif
80
81# The following example constructs an expression with the variable name ""
82# and the value " ".  This expression counts as empty since the value contains
83# only whitespace.
84#
85# Contrary to the other functions in conditionals, the trailing space is not
86# stripped off, as can be seen in the -dv debug log.  If the space had been
87# stripped, it wouldn't make a difference in this case, but in other cases.
88#
89.if !empty(:U )
90.  error
91.endif
92
93# Now the variable named " " gets a non-empty value, which demonstrates that
94# neither leading nor trailing spaces are trimmed in the argument of the
95# function.  If the spaces were trimmed, the variable name would be "" and
96# that variable is indeed undefined.  Since CondParser_FuncCallEmpty calls
97# Var_Parse without VARE_UNDEFERR, the value of the undefined variable ""
98# would be returned as an empty string.
99${:U }=	space
100.if empty( )
101.  error
102.endif
103
104# The value of the following expression is " word", which is not empty.
105.if empty(:U word)
106.  error
107.endif
108
109# The :L modifier creates a variable expression that has the same value as
110# its name, which both are "VAR" in this case.  The value is therefore not
111# empty.
112.if empty(VAR:L)
113.  error
114.endif
115
116# The variable WORD has the value "word", which does not count as empty.
117.if empty(WORD)
118.  error
119.endif
120
121# The expression ${} for a variable with the empty name always evaluates
122# to an empty string (see Var_Parse, varUndefined).
123.if !empty()
124.  error
125.endif
126
127# Ensure that variable expressions that appear as part of the function call
128# argument are properly parsed.  Typical use cases for this are .for loops,
129# which are expanded to exactly these ${:U} expressions.
130#
131# If everything goes well, the argument expands to "WORD", and that variable
132# is defined at the beginning of this file.  The surrounding 'W' and 'D'
133# ensure that CondParser_FuncCallEmpty keeps track of the parsing position,
134# both before and after the call to Var_Parse.
135.if empty(W${:UOR}D)
136.  error
137.endif
138
139# There may be spaces at the outside of the parentheses.
140# Spaces inside the parentheses are interpreted as part of the variable name.
141.if ! empty ( WORD )
142.  error
143.endif
144
145${:U WORD }=	variable name with spaces
146
147# Now there is a variable named " WORD ", and it is not empty.
148.if empty ( WORD )
149.  error
150.endif
151
152# expect+2: Unclosed variable "WORD"
153# expect+1: Malformed conditional (empty(WORD)
154.if empty(WORD
155.  error
156.else
157.  error
158.endif
159
160# Since cond.c 1.76 from 2020-06-28 and before var.c 1.226 from 2020-07-02,
161# the following example generated a wrong error message "Variable VARNAME is
162# recursive".
163#
164# Since at least 1993, the manual page claimed that irrelevant parts of
165# conditions were not evaluated, but that was wrong for a long time.  The
166# expressions in irrelevant parts of the condition were actually evaluated,
167# they just allowed undefined variables to be used in the conditions.  These
168# unnecessary evaluations were fixed in several commits, starting with var.c
169# 1.226 from 2020-07-02.
170#
171# In this example, the variable "VARNAME2" is not defined, so evaluation of
172# the condition should have stopped at this point, and the rest of the
173# condition should have been processed in parse-only mode.  The right-hand
174# side containing the '!empty' was evaluated though, as it had always been.
175#
176# When evaluating the !empty condition, the variable name was parsed as
177# "VARNAME${:U2}", but without expanding any nested variable expression, in
178# this case the ${:U2}.  The expression '${:U2}' was replaced with an empty
179# string, the resulting variable name was thus "VARNAME".  This conceptually
180# wrong variable name should have been discarded quickly after parsing it, to
181# prevent it from doing any harm.
182#
183# The variable expression was expanded though, and this was wrong.  The
184# expansion was done without VARE_WANTRES (called VARF_WANTRES back
185# then) though.  This had the effect that the ${:U1} from the value of VARNAME
186# expanded to an empty string.  This in turn created the seemingly recursive
187# definition VARNAME=${VARNAME}, and that definition was never meant to be
188# expanded.
189#
190# This was fixed by expanding nested variable expressions in the variable name
191# only if the flag VARE_WANTRES is given.
192VARNAME=	${VARNAME${:U1}}
193.if defined(VARNAME${:U2}) && !empty(VARNAME${:U2})
194.endif
195
196
197# If the word 'empty' is not followed by '(', it is not a function call but an
198# ordinary bare word.  This bare word is interpreted as 'defined(empty)', and
199# since there is no variable named 'empty', the condition evaluates to false.
200.if empty
201.  error
202.endif
203
204empty=		# defined but empty
205.if empty
206.else
207.  error
208.endif
209