Home | History | Annotate | Line # | Download | only in unit-tests
      1 # $NetBSD: varname.mk,v 1.18 2025/06/28 22:39:29 rillig Exp $
      2 #
      3 # Tests for variable names.
      4 
      5 .MAKEFLAGS: -dv
      6 
      7 # In a variable assignment, braces are allowed in the variable name, but they
      8 # must be balanced.  Parentheses and braces may be mixed.
      9 VAR{{{}}}=	3 braces
     10 .if "${VAR{{{}}}}" != "3 braces"
     11 .  error
     12 .endif
     13 
     14 # In expressions, the parser works differently.  It doesn't treat
     15 # braces and parentheses equally, therefore the first closing brace already
     16 # marks the end of the variable name.
     17 VARNAME=	VAR(((
     18 ${VARNAME}=	3 open parentheses
     19 .if "${VAR(((}}}}" != "3 open parentheses}}}"
     20 .  error
     21 .endif
     22 
     23 # In the above test, the variable name is constructed indirectly.  Neither
     24 # of the following expressions produces the intended effect.
     25 #
     26 # This is not a variable assignment since the parentheses and braces are not
     27 # balanced.  At the end of the line, there are still 3 levels open, which
     28 # means the variable name is not finished.
     29 # expect+2: Missing ")" in archive specification
     30 # expect+1: Error in archive specification: "VAR"
     31 ${:UVAR(((}=	try1
     32 # On the left-hand side of a variable assignments, the backslash is not parsed
     33 # as an escape character, therefore the parentheses still count to the nesting
     34 # level, which at the end of the line is still 3.  Therefore this is not a
     35 # variable assignment as well.
     36 # expect+1: Invalid line "${:UVAR\(\(\(}=	try2", expanded to "VAR\(\(\(=	try2"
     37 ${:UVAR\(\(\(}=	try2
     38 # To assign to a variable with an arbitrary name, the variable name has to
     39 # come from an external source, not the text that is parsed in the assignment
     40 # itself.  This is exactly the reason why further above, the indirect
     41 # ${VARNAME} works, while all other attempts fail.
     42 ${VARNAME}=	try3
     43 
     44 .MAKEFLAGS: -d0
     45 
     46 # All variable names of a scope are stored in the same hash table, using a
     47 # simple hash function.  Ensure that HashTable_Find handles collisions
     48 # correctly and that the correct variable is looked up.  The strings "0x" and
     49 # "1Y" have the same hash code, as 31 * '0' + 'x' == 31 * '1' + 'Y'.
     50 V.0x=	0x
     51 V.1Y=	1Y
     52 .if ${V.0x} != "0x" || ${V.1Y} != "1Y"
     53 .  error
     54 .endif
     55 
     56 # The string "ASDZguv", when used as a prefix of a variable name, keeps the
     57 # hash code unchanged, its own hash code is 0.
     58 ASDZguvV.0x=	0x
     59 ASDZguvV.1Y=	1Y
     60 .if ${ASDZguvV.0x} != "0x"
     61 .  error
     62 .elif ${ASDZguvV.1Y} != "1Y"
     63 .  error
     64 .endif
     65 
     66 # Ensure that variables with the same hash code whose name is a prefix of the
     67 # other can be accessed.  In this case, the shorter variable name is defined
     68 # first to make it appear later in the bucket of the hash table.
     69 ASDZguv=	once
     70 ASDZguvASDZguv=	twice
     71 .if ${ASDZguv} != "once"
     72 .  error
     73 .elif ${ASDZguvASDZguv} != "twice"
     74 .  error
     75 .endif
     76 
     77 # Ensure that variables with the same hash code whose name is a prefix of the
     78 # other can be accessed.  In this case, the longer variable name is defined
     79 # first to make it appear later in the bucket of the hash table.
     80 ASDZguvASDZguv.param=	twice
     81 ASDZguv.param=		once
     82 .if ${ASDZguv.param} != "once"
     83 .  error
     84 .elif ${ASDZguvASDZguv.param} != "twice"
     85 .  error
     86 .endif
     87 
     88 
     89 # Warn about expressions in the style of GNU make, as these would silently
     90 # expand to an empty string instead.
     91 #
     92 # https://pubs.opengroup.org/onlinepubs/9799919799/utilities/make.html says:
     93 #	a macro name shall not contain an <equals-sign>, <blank>, or control
     94 #	character.
     95 #
     96 GNU_MAKE_IF=	$(if ${HAVE_STRLEN},yes,no)
     97 # expect+1: warning: Invalid character " " in variable name "if ,yes,no"
     98 .if ${GNU_MAKE_IF} != ""
     99 .  error
    100 .endif
    101 #
    102 # This requirement needs to be ignored for expressions with a ":L" or ":?:"
    103 # modifier, as these modifiers rely on arbitrary characters in the expression
    104 # name.
    105 .if ${"left" == "right":?equal:unequal} != "unequal"
    106 .  error
    107 .endif
    108 #
    109 # In fact, this requirement is ignored for any expression that has a modifier.
    110 # In this indirect case, though, the expression with the space in the name is
    111 # a nested expression, so the ":U" modifier doesn't affect the warning.
    112 # expect+1: warning: Invalid character " " in variable name "if ,yes,no"
    113 .if ${GNU_MAKE_IF:Ufallback} != ""
    114 .  error
    115 .endif
    116 #
    117 # A modifier in a nested expression does not affect the warning.
    118 GNU_MAKE_IF_EXPR=	$(if ${HAVE_STRLEN},${HEADERS:.h=.c},)
    119 # expect+1: warning: Invalid character " " in variable name "if ,,"
    120 .if ${GNU_MAKE_IF_EXPR} != ""
    121 .  error
    122 .endif
    123 #
    124 # When the GNU make expression contains a colon, chances are good that the
    125 # colon is interpreted as an unknown modifier.
    126 GNU_MAKE_IF_MODIFIER=	$(if ${HAVE_STRLEN},answer:yes,answer:no)
    127 # expect+1: Unknown modifier ":yes,answer"
    128 .if ${GNU_MAKE_IF_MODIFIER} != "no)"
    129 .  error
    130 .endif
    131 #
    132 # If the variable name contains a non-printable character, the warning
    133 # contains the numeric character value instead, to prevent control sequences
    134 # in the output.
    135 CONTROL_CHARACTER=	${:U a b:ts\t}
    136 # expect+2: warning: Invalid character "\x09" in variable name "a	b"
    137 # expect+1: Variable "a	b" is undefined
    138 .if ${${CONTROL_CHARACTER}} != ""
    139 .endif
    140 #
    141 # For now, only whitespace generates a warning, non-ASCII characters don't.
    142 UMLAUT=		
    143 # expect+1: Variable "" is undefined
    144 .if ${${UMLAUT}} != ""
    145 .endif
    146