Home | History | Annotate | Line # | Download | only in unit-tests
varmod.mk revision 1.17
      1 # $NetBSD: varmod.mk,v 1.17 2024/07/04 18:53:37 rillig Exp $
      2 #
      3 # Tests for variable modifiers, such as :Q, :S,from,to or :Ufallback.
      4 #
      5 # See also:
      6 #	varparse-errors.mk
      7 
      8 # As of 2024-06-05, the possible behaviors during parsing are:
      9 #
     10 # * `strict`: the parsing style used by most modifiers:
     11 #   * either uses `ParseModifierPart` or parses the modifier literal
     12 #   * other modifiers may follow, separated by a ':'
     13 #
     14 # * `greedy`: calls `ParseModifierPart` with `ch->endc`; this means
     15 #   that no further modifiers are parsed in that expression.
     16 #
     17 # * `no-colon`: after parsing this modifier, the following modifier
     18 #   does not need to be separated by a colon.
     19 #   Omitting this colon is bad style.
     20 #
     21 # * `individual`: parsing this modifier does not follow the common
     22 #   pattern of calling `ParseModifierPart`.
     23 #
     24 # The SysV column says whether a parse error in the modifier falls back
     25 # trying the `:from=to` System V modifier.
     26 #
     27 # | **Operator** | **Behavior** | **Remarks**        | **SysV** |
     28 # |--------------|--------------|--------------------|----------|
     29 # | `!`          | no-colon     |                    | no       |
     30 # | `:=`         | greedy       |                    | yes      |
     31 # | `?:`         | greedy       |                    | no       |
     32 # | `@`          | no-colon     |                    | no       |
     33 # | `C`          | no-colon     |                    | no       |
     34 # | `D`          | individual   | custom parser      | N/A      |
     35 # | `E`          | strict       |                    | yes      |
     36 # | `H`          | strict       |                    | yes      |
     37 # | `L`          | no-colon     |                    | N/A      |
     38 # | `M`          | individual   | custom parser      | N/A      |
     39 # | `N`          | individual   | custom parser      | N/A      |
     40 # | `O`          | strict       | only literal value | no       |
     41 # | `P`          | no-colon     |                    | N/A      |
     42 # | `Q`          | strict       |                    | yes      |
     43 # | `R`          | strict       |                    | yes      |
     44 # | `S`          | no-colon     |                    | N/A      |
     45 # | `T`          | strict       |                    | N/A      |
     46 # | `U`          | individual   | custom parser      | N/A      |
     47 # | `[`          | strict       |                    | no       |
     48 # | `_`          | individual   | strcspn            | yes      |
     49 # | `gmtime`     | strict       |                    | yes      |
     50 # | `hash`       | strict       |                    | N/A      |
     51 # | `localtime`  | strict       |                    | yes      |
     52 # | `q`          | strict       |                    | yes      |
     53 # | `range`      | strict       |                    | N/A      |
     54 # | `sh`         | strict       |                    | N/A      |
     55 # | `t`          | strict       |                    | no       |
     56 # | `u`          | strict       |                    | yes      |
     57 # | `from=to`    | greedy       | SysV, fallback     | N/A      |
     58 
     59 # These tests assume
     60 .MAKE.SAVE_DOLLARS = yes
     61 
     62 DOLLAR1=	$$
     63 DOLLAR2=	${:U\$}
     64 
     65 # To get a single '$' sign in the value of an expression, it has to
     66 # be written as '$$' in a literal variable value.
     67 #
     68 # See Var_Parse, where it calls Var_Subst.
     69 .if ${DOLLAR1} != "\$"
     70 .  error
     71 .endif
     72 
     73 # Another way to get a single '$' sign is to use the :U modifier.  In the
     74 # argument of that modifier, a '$' is escaped using the backslash instead.
     75 #
     76 # See Var_Parse, where it calls Var_Subst.
     77 .if ${DOLLAR2} != "\$"
     78 .  error
     79 .endif
     80 
     81 # It is also possible to use the :U modifier directly in the expression.
     82 #
     83 # See Var_Parse, where it calls Var_Subst.
     84 .if ${:U\$} != "\$"
     85 .  error
     86 .endif
     87 
     88 # XXX: As of 2020-09-13, it is not possible to use '$$' in a variable name
     89 # to mean a single '$'.  This contradicts the manual page, which says that
     90 # '$' can be escaped as '$$'.
     91 .if ${$$:L} != ""
     92 .  error
     93 .endif
     94 
     95 # In lint mode, make prints helpful error messages.
     96 # For compatibility, make does not print these error messages in normal mode.
     97 # Should it?
     98 .MAKEFLAGS: -dL
     99 # expect+2: To escape a dollar, use \$, not $$, at "$$:L} != """
    100 # expect+1: Invalid variable name ':', at "$:L} != """
    101 .if ${$$:L} != ""
    102 .  error
    103 .endif
    104 
    105 # A '$' followed by nothing is an error as well.
    106 # expect+1: while evaluating "${:Uword:@word@${word}$@} != "word"": Dollar followed by nothing
    107 .if ${:Uword:@word@${word}$@} != "word"
    108 .  error
    109 .endif
    110 
    111 # The variable modifier :P does not fall back to the SysV modifier.
    112 # Therefore the modifier :P=RE generates a parse error.
    113 # XXX: The .error should not be reached since the expression is
    114 # malformed, and this error should be propagated up to Cond_EvalLine.
    115 VAR=	STOP
    116 # expect+1: while evaluating variable "VAR" with value "VAR": Missing delimiter ':' after modifier "P"
    117 .if ${VAR:P=RE} != "STORE"
    118 # expect+1: Missing argument for ".error"
    119 .  error
    120 .endif
    121 
    122 # Test the word selection modifier ':[n]' with a very large number that is
    123 # larger than ULONG_MAX for any supported platform.
    124 # expect+2: while evaluating variable "word" with value "word": Bad modifier ":[99333000222000111000]"
    125 # expect+1: Malformed conditional (${word:L:[99333000222000111000]})
    126 .if ${word:L:[99333000222000111000]}
    127 .endif
    128 # expect+2: while evaluating variable "word" with value "word": Bad modifier ":[2147483648]"
    129 # expect+1: Malformed conditional (${word:L:[2147483648]})
    130 .if ${word:L:[2147483648]}
    131 .endif
    132 
    133 # Test the range generation modifier ':range=n' with a very large number that
    134 # is larger than SIZE_MAX for any supported platform.
    135 # expect+2: Malformed conditional (${word:L:range=99333000222000111000})
    136 # expect+1: while evaluating variable "word" with value "word": Invalid number "99333000222000111000}" for ':range' modifier
    137 .if ${word:L:range=99333000222000111000}
    138 .endif
    139 
    140 # In an indirect modifier, the delimiter is '\0', which at the same time marks
    141 # the end of the string.  The sequence '\\' '\0' is not an escaped delimiter,
    142 # as it would be wrong to skip past the end of the string.
    143 # expect+2: while evaluating "${:${:Ugmtime=\\}}": Invalid time value "\"
    144 # expect+1: Malformed conditional (${:${:Ugmtime=\\}})
    145 .if ${:${:Ugmtime=\\}}
    146 .  error
    147 .endif
    148 
    149 # Test a '$' at the end of a modifier part, for all modifiers in the order
    150 # listed in ApplyModifier.
    151 #
    152 # The only modifier parts where an unescaped '$' makes sense at the end are
    153 # the 'from' parts of the ':S' and ':C' modifiers.  In all other modifier
    154 # parts, an unescaped '$' is an undocumented and discouraged edge case, as it
    155 # means the same as an escaped '$'.
    156 .if ${:U:!printf '%s\n' $!} != "\$"
    157 .  error
    158 .endif
    159 # expect+1: while evaluating variable "VAR" with value "value$": Dollar followed by nothing
    160 .if ${VAR::=value$} != "" || ${VAR} != "value"
    161 .  error
    162 .endif
    163 ${:U }=		<space>
    164 # expect+2: while evaluating variable "VAR" with value "value$": Dollar followed by nothing
    165 # expect+1: while evaluating variable "VAR" with value "value$ appended$": Dollar followed by nothing
    166 .if ${VAR::+=appended$} != "" || ${VAR} != "value<space>appended"
    167 .  error
    168 .endif
    169 .if ${1:?then$:else$} != "then\$"
    170 .  error
    171 .endif
    172 .if ${0:?then$:else$} != "else\$"
    173 .  error
    174 .endif
    175 # expect+1: while evaluating variable "word" with value "word": Dollar followed by nothing
    176 .if ${word:L:@w@$w$@} != "word"
    177 .  error
    178 .endif
    179 # expect+2: while evaluating variable "word" with value "": Bad modifier ":[$]"
    180 # expect+1: Malformed conditional (${word:[$]})
    181 .if ${word:[$]}
    182 .  error
    183 .else
    184 .  error
    185 .endif
    186 VAR_DOLLAR=	VAR$$
    187 .if ${word:L:_=VAR$} != "word" || ${${VAR_DOLLAR}} != "word"
    188 .  error
    189 .endif
    190 .if ${word:L:C,d$,m,} != "worm"
    191 .  error
    192 .endif
    193 .if ${word:L:C,d,$,} != "wor\$"
    194 .  error
    195 .endif
    196 # expect+2: while evaluating variable "VAR" with value "value$ appended$": Dollar followed by nothing
    197 # expect+1: while evaluating variable "VAR" with value "value<space>appended": Invalid variable name '}', at "$} != "set""
    198 .if ${VAR:Dset$} != "set"
    199 .  error
    200 .endif
    201 # expect+1: while evaluating "${:Ufallback$} != "fallback"": Invalid variable name '}', at "$} != "fallback""
    202 .if ${:Ufallback$} != "fallback"
    203 .  error
    204 .endif
    205 # expect+2: Malformed conditional (${%y:L:gmtime=1000$})
    206 # expect+1: while evaluating variable "%y" with value "%y": Invalid time value "1000$"
    207 .if ${%y:L:gmtime=1000$}
    208 .  error
    209 .else
    210 .  error
    211 .endif
    212 # expect+2: Malformed conditional (${%y:L:localtime=1000$})
    213 # expect+1: while evaluating variable "%y" with value "%y": Invalid time value "1000$"
    214 .if ${%y:L:localtime=1000$}
    215 .  error
    216 .else
    217 .  error
    218 .endif
    219 # expect+1: while evaluating variable "word" with value "word": Dollar followed by nothing
    220 .if ${word:L:Mw*$} != "word"
    221 .  error
    222 .endif
    223 # expect+1: while evaluating variable "word" with value "word": Dollar followed by nothing
    224 .if ${word:L:NX*$} != "word"
    225 .  error
    226 .endif
    227 # expect+2: while evaluating variable "." with value ".": Invalid argument 'fallback$' for modifier ':mtime'
    228 # expect+1: Malformed conditional (${.:L:mtime=fallback$})
    229 .if ${.:L:mtime=fallback$}
    230 .  error
    231 .else
    232 .  error
    233 .endif
    234 .if ${word:L:S,d$,m,} != "worm"
    235 .  error
    236 .endif
    237 .if ${word:L:S,d,m$,} != "worm\$"
    238 .  error
    239 .endif
    240