xref: /freebsd/contrib/bmake/unit-tests/cond-func-empty.mk (revision dd41de95a84d979615a2ef11df6850622bf6184e)
1# $NetBSD: cond-func-empty.mk,v 1.11 2020/11/28 14:08:37 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 indeed a variable name,
7# 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.  The
28# expression is now no longer empty, but it is still possible to see whether
29# the expression was based on an undefined variable.  The expression has the
30# flag VEF_UNDEF.
31#
32# The expression does not have the flag VEF_DEF though, therefore it is still
33# considered undefined.  Yes, indeed, undefined but not empty.  There are a
34# few variable modifiers that turn an undefined expression into a defined
35# expression, among them :U and :D, but not :S.
36#
37# XXX: This is hard to explain to someone who doesn't know these
38# implementation details.
39#
40.if !empty(UNDEF:S,^$,value,W)
41.  error
42.endif
43
44# The :U modifier modifies expressions based on undefined variables
45# (VAR_JUNK) by adding the VAR_KEEP flag, which marks the expression
46# as "being interesting enough to be further processed".
47#
48.if empty(UNDEF:S,^$,value,W:Ufallback)
49.  error
50.endif
51
52# And now to the surprising part.  Applying the following :S modifier to the
53# undefined expression makes it non-empty, but the marker VEF_UNDEF is
54# preserved nevertheless.  The :U modifier that follows only looks at the
55# VEF_UNDEF flag to decide whether the variable is defined or not.  This kind
56# of makes sense since the :U modifier tests the _variable_, not the
57# _expression_.
58#
59# But since the variable was undefined to begin with, the fallback value from
60# the :U modifier is used in this expression.
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 empty variable named "" gets a fallback value of " ", which counts as
82# empty.
83#
84# Contrary to the other functions in conditionals, the trailing space is not
85# stripped off, as can be seen in the -dv debug log.  If the space had been
86# stripped, it wouldn't make a difference in this case.
87#
88.if !empty(:U )
89.  error
90.endif
91
92# Now the variable named " " gets a non-empty value, which demonstrates that
93# neither leading nor trailing spaces are trimmed in the argument of the
94# function.  If the spaces were trimmed, the variable name would be "" and
95# that variable is indeed undefined.  Since ParseEmptyArg calls Var_Parse
96# without VARE_UNDEFERR, the value of the undefined variable is returned as
97# an empty string.
98${:U }=	space
99.if empty( )
100.  error
101.endif
102
103# The value of the following expression is " word", which is not empty.
104.if empty(:U word)
105.  error
106.endif
107
108# The :L modifier creates a variable expression that has the same value as
109# its name, which both are "VAR" in this case.  The value is therefore not
110# empty.
111.if empty(VAR:L)
112.  error
113.endif
114
115# The variable WORD has the value "word", which does not count as empty.
116.if empty(WORD)
117.  error
118.endif
119
120# The expression ${} for a variable with the empty name always evaluates
121# to an empty string (see Var_Parse, varUndefined).
122.if !empty()
123.  error
124.endif
125
126# Ensure that variable expressions that appear as part of the argument are
127# properly parsed.  Typical use cases for this are .for loops, which are
128# expanded to exactly these ${:U} expressions.
129#
130# If everything goes well, the argument expands to "WORD", and that variable
131# is defined at the beginning of this file.  The surrounding 'W' and 'D'
132# ensure that the parser in ParseEmptyArg has the correct position, both
133# before and after the call to Var_Parse.
134.if empty(W${:UOR}D)
135.  error
136.endif
137
138# There may be spaces at the outside of the parentheses.
139# Spaces inside the parentheses are interpreted as part of the variable name.
140.if ! empty ( WORD )
141.  error
142.endif
143
144${:U WORD }=	variable name with spaces
145
146# Now there is a variable named " WORD ", and it is not empty.
147.if empty ( WORD )
148.  error
149.endif
150
151# Parse error: missing closing parenthesis.
152.if empty(WORD
153.  error
154.else
155.  error
156.endif
157
158# Between 2020-06-28 and var.c 1.226 from 2020-07-02, this paragraph generated
159# a wrong error message "Variable VARNAME is recursive".
160#
161# The bug was that the !empty() condition was evaluated, even though this was
162# not necessary since the defined() condition already evaluated to false.
163#
164# When evaluating the !empty condition, the variable name was parsed as
165# "VARNAME${:U2}", but without expanding any nested variable expression, in
166# this case the ${:U2}.  Therefore, the variable name came out as simply
167# "VARNAME".  Since this variable name should have been discarded quickly after
168# parsing it, this unrealistic variable name should have done no harm.
169#
170# The variable expression was expanded though, and this was wrong.  The
171# expansion was done without the VARE_WANTRES flag (called VARF_WANTRES back
172# then) though.  This had the effect that the ${:U1} from the value of VARNAME
173# expanded to an empty string.  This in turn created the seemingly recursive
174# definition VARNAME=${VARNAME}, and that definition was never meant to be
175# expanded.
176#
177# This was fixed by expanding nested variable expressions in the variable name
178# only if the flag VARE_WANTRES is given.
179VARNAME=	${VARNAME${:U1}}
180.if defined(VARNAME${:U2}) && !empty(VARNAME${:U2})
181.endif
182
183all:
184	@:;
185