1# NOTE: Tests related to isDeclaredMap go here. 2{ 3 isDeclaredMap, 4 lib, 5 runCommand, 6 testers, 7}: 8let 9 inherit (lib.attrsets) recurseIntoAttrs; 10 inherit (testers) shellcheck shfmt testBuildFailure'; 11 12 commonArgs = { 13 __structuredAttrs = true; 14 strictDeps = true; 15 preferLocalBuild = true; 16 nativeBuildInputs = [ isDeclaredMap ]; 17 }; 18 19 check = 20 let 21 mkLine = 22 intro: values: 23 "${if intro == null then "" else intro + " "}check${if values == null then "" else "=" + values}"; 24 mkScope = 25 scope: line: 26 if scope == null then 27 line 28 else if scope == "function" then 29 '' 30 foo() { 31 ${line} 32 } 33 foo 34 '' 35 else 36 builtins.throw "Invalid scope: ${scope}"; 37 in 38 { 39 name, 40 scope, 41 intro, 42 values, 43 }: 44 runCommand name commonArgs '' 45 set -eu 46 47 ${mkScope scope (mkLine intro values)} 48 49 if isDeclaredMap check; then 50 nixLog "test passed" 51 touch "$out" 52 else 53 nixErrorLog "test failed" 54 exit 1 55 fi 56 ''; 57in 58recurseIntoAttrs { 59 shellcheck = shellcheck { 60 name = "isDeclaredMap"; 61 src = ./isDeclaredMap.bash; 62 }; 63 64 shfmt = shfmt { 65 name = "isDeclaredMap"; 66 src = ./isDeclaredMap.bash; 67 }; 68 69 undeclaredFails = testBuildFailure' { 70 name = "undeclaredFails"; 71 drv = runCommand "undeclared" commonArgs '' 72 set -eu 73 if isDeclaredMap undeclared; then 74 nixLog "test passed" 75 touch "$out" 76 else 77 nixErrorLog "test failed" 78 exit 1 79 fi 80 ''; 81 expectedBuilderLogEntries = [ 82 "test failed" 83 ]; 84 }; 85 86 arrayFails = testBuildFailure' { 87 name = "arrayFails"; 88 drv = runCommand "array" commonArgs '' 89 set -eu 90 local -a array 91 if isDeclaredMap array; then 92 nixLog "test passed" 93 touch "$out" 94 else 95 nixErrorLog "test failed" 96 exit 1 97 fi 98 ''; 99 expectedBuilderLogEntries = [ 100 "test failed" 101 ]; 102 }; 103 104 emptyStringNamerefFails = testBuildFailure' { 105 name = "emptyStringNamerefFails"; 106 drv = runCommand "emptyStringNameref" commonArgs '' 107 set -eu 108 if isDeclaredMap ""; then 109 nixLog "test passed" 110 touch "$out" 111 else 112 nixErrorLog "test failed" 113 exit 1 114 fi 115 ''; 116 expectedBuilderLogEntries = [ 117 "local: `': not a valid identifier" 118 "test failed" 119 ]; 120 }; 121 122 namerefToEmptyStringFails = testBuildFailure' { 123 name = "namerefToEmptyStringFails"; 124 drv = check { 125 name = "namerefToEmptyString"; 126 scope = null; 127 intro = "local -n"; 128 values = ""; 129 }; 130 expectedBuilderLogEntries = [ 131 "local: `': not a valid identifier" 132 # The test fails in such a way that it exits immediately, without returning to the else branch. 133 ]; 134 }; 135 136 sameScopeEmptyStringFails = testBuildFailure' { 137 name = "sameScopeEmptyStringFails"; 138 drv = check { 139 name = "sameScopeEmptyString"; 140 scope = null; 141 intro = null; 142 values = ""; 143 }; 144 expectedBuilderLogEntries = [ 145 "test failed" 146 ]; 147 }; 148 149 sameScopeEmptyMapFails = testBuildFailure' { 150 name = "sameScopeEmptyMapFails"; 151 drv = check { 152 name = "sameScopeEmptyMap"; 153 scope = null; 154 intro = null; 155 values = "()"; 156 }; 157 expectedBuilderLogEntries = [ 158 "test failed" 159 ]; 160 }; 161 162 # Fails because maps must be declared with the -A flag. 163 sameScopeSingletonMapFails = testBuildFailure' { 164 name = "sameScopeSingletonMapFails"; 165 drv = check { 166 name = "sameScopeSingletonMap"; 167 scope = null; 168 intro = null; 169 values = ''([greeting]="hello!")''; 170 }; 171 expectedBuilderLogEntries = [ 172 "greeting: unbound variable" 173 ]; 174 }; 175 176 sameScopeLocalUnsetMap = check { 177 name = "sameScopeLocalUnsetMap"; 178 scope = null; 179 intro = "local -A"; 180 values = null; 181 }; 182 183 sameScopeLocalEmptyMap = check { 184 name = "sameScopeLocalEmptyMap"; 185 scope = null; 186 intro = "local -A"; 187 values = "()"; 188 }; 189 190 sameScopeLocalSingletonMap = check { 191 name = "sameScopeLocalSingletonMap"; 192 scope = null; 193 intro = "local -A"; 194 values = ''([greeting]="hello!")''; 195 }; 196 197 sameScopeDeclareUnsetMap = check { 198 name = "sameScopeDeclareUnsetMap"; 199 scope = null; 200 intro = "declare -A"; 201 values = null; 202 }; 203 204 sameScopeDeclareEmptyMap = check { 205 name = "sameScopeDeclareEmptyMap"; 206 scope = null; 207 intro = "declare -A"; 208 values = "()"; 209 }; 210 211 sameScopeDeclareSingletonMap = check { 212 name = "sameScopeDeclareSingletonMap"; 213 scope = null; 214 intro = "declare -A"; 215 values = ''([greeting]="hello!")''; 216 }; 217 218 previousScopeEmptyStringFails = testBuildFailure' { 219 name = "previousScopeEmptyStringFails"; 220 drv = check { 221 name = "previousScopeEmptyString"; 222 scope = "function"; 223 intro = null; 224 values = ""; 225 }; 226 expectedBuilderLogEntries = [ 227 "test failed" 228 ]; 229 }; 230 231 # Fails because () is ambiguous and defaults to array rather than associative array. 232 previousScopeEmptyMapFails = testBuildFailure' { 233 name = "previousScopeEmptyMapFails"; 234 drv = check { 235 name = "previousScopeEmptyMap"; 236 scope = "function"; 237 intro = null; 238 values = "()"; 239 }; 240 expectedBuilderLogEntries = [ 241 "test failed" 242 ]; 243 }; 244 245 previousScopeSingletonMapFails = testBuildFailure' { 246 name = "previousScopeSingletonMapFails"; 247 drv = check { 248 name = "previousScopeSingletonMap"; 249 scope = "function"; 250 intro = null; 251 values = ''([greeting]="hello!")''; 252 }; 253 expectedBuilderLogEntries = [ 254 "greeting: unbound variable" 255 ]; 256 }; 257 258 previousScopeLocalUnsetMapFails = testBuildFailure' { 259 name = "previousScopeLocalUnsetMapFails"; 260 drv = check { 261 name = "previousScopeLocalUnsetMap"; 262 scope = "function"; 263 intro = "local -A"; 264 values = null; 265 }; 266 expectedBuilderLogEntries = [ 267 "test failed" 268 ]; 269 }; 270 271 previousScopeLocalEmptyMapFails = testBuildFailure' { 272 name = "previousScopeLocalEmptyMapFails"; 273 drv = check { 274 name = "previousScopeLocalEmptyMap"; 275 scope = "function"; 276 intro = "local -A"; 277 values = "()"; 278 }; 279 expectedBuilderLogEntries = [ 280 "test failed" 281 ]; 282 }; 283 284 previousScopeLocalSingletonMapFails = testBuildFailure' { 285 name = "previousScopeLocalSingletonMapFails"; 286 drv = check { 287 name = "previousScopeLocalSingletonMap"; 288 scope = "function"; 289 intro = "local -A"; 290 values = ''([greeting]="hello!")''; 291 }; 292 expectedBuilderLogEntries = [ 293 "test failed" 294 ]; 295 }; 296 297 previousScopeLocalGlobalUnsetMap = check { 298 name = "previousScopeLocalGlobalUnsetMap"; 299 scope = "function"; 300 intro = "local -Ag"; 301 values = null; 302 }; 303 304 previousScopeLocalGlobalEmptyMap = check { 305 name = "previousScopeLocalGlobalEmptyMap"; 306 scope = "function"; 307 intro = "local -Ag"; 308 values = "()"; 309 }; 310 311 previousScopeLocalGlobalSingletonMap = check { 312 name = "previousScopeLocalGlobalSingletonMap"; 313 scope = "function"; 314 intro = "local -Ag"; 315 values = ''([greeting]="hello!")''; 316 }; 317 318 previousScopeDeclareUnsetMapFails = testBuildFailure' { 319 name = "previousScopeDeclareUnsetMapFails"; 320 drv = check { 321 name = "previousScopeDeclareUnsetMap"; 322 scope = "function"; 323 intro = "declare -A"; 324 values = null; 325 }; 326 expectedBuilderLogEntries = [ 327 "test failed" 328 ]; 329 }; 330 331 previousScopeDeclareEmptyMapFails = testBuildFailure' { 332 name = "previousScopeDeclareEmptyMapFails"; 333 drv = check { 334 name = "previousScopeDeclareEmptyMap"; 335 scope = "function"; 336 intro = "declare -A"; 337 values = "()"; 338 }; 339 expectedBuilderLogEntries = [ 340 "test failed" 341 ]; 342 }; 343 344 previousScopeDeclareSingletonMapFails = testBuildFailure' { 345 name = "previousScopeDeclareSingletonMapFails"; 346 drv = check { 347 name = "previousScopeDeclareSingletonMap"; 348 scope = "function"; 349 intro = "declare -A"; 350 values = ''([greeting]="hello!")''; 351 }; 352 expectedBuilderLogEntries = [ 353 "test failed" 354 ]; 355 }; 356 357 previousScopeDeclareGlobalUnsetMap = check { 358 name = "previousScopeDeclareGlobalUnsetMap"; 359 scope = "function"; 360 intro = "declare -Ag"; 361 values = null; 362 }; 363 364 previousScopeDeclareGlobalEmptyMap = check { 365 name = "previousScopeDeclareGlobalEmptyMap"; 366 scope = "function"; 367 intro = "declare -Ag"; 368 values = "()"; 369 }; 370 371 previousScopeDeclareGlobalSingletonMap = check { 372 name = "previousScopeDeclareGlobalSingletonMap"; 373 scope = "function"; 374 intro = "declare -Ag"; 375 values = ''([greeting]="hello!")''; 376 }; 377}