1# NOTE: Tests related to isDeclaredArray go here. 2{ 3 isDeclaredArray, 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 = [ isDeclaredArray ]; 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 isDeclaredArray 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 = "isDeclaredArray"; 61 src = ./isDeclaredArray.bash; 62 }; 63 64 shfmt = shfmt { 65 name = "isDeclaredArray"; 66 src = ./isDeclaredArray.bash; 67 }; 68 69 undeclaredFails = testBuildFailure' { 70 name = "undeclaredFails"; 71 drv = runCommand "undeclared" commonArgs '' 72 set -eu 73 if isDeclaredArray 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 mapFails = testBuildFailure' { 87 name = "mapFails"; 88 drv = runCommand "map" commonArgs '' 89 set -eu 90 local -A map 91 if isDeclaredArray map; 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 isDeclaredArray ""; 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 sameScopeEmptyArray = check { 150 name = "sameScopeEmptyArray"; 151 scope = null; 152 intro = null; 153 values = "()"; 154 }; 155 156 sameScopeSingletonArray = check { 157 name = "sameScopeSingletonArray"; 158 scope = null; 159 intro = null; 160 values = ''("hello!")''; 161 }; 162 163 sameScopeLocalUnsetArray = check { 164 name = "sameScopeLocalUnsetArray"; 165 scope = null; 166 intro = "local -a"; 167 values = null; 168 }; 169 170 sameScopeLocalEmptyArray = check { 171 name = "sameScopeLocalEmptyArray"; 172 scope = null; 173 intro = "local -a"; 174 values = "()"; 175 }; 176 177 sameScopeLocalSingletonArray = check { 178 name = "sameScopeLocalSingletonArray"; 179 scope = null; 180 intro = "local -a"; 181 values = ''("hello!")''; 182 }; 183 184 sameScopeDeclareUnsetArray = check { 185 name = "sameScopeDeclareUnsetArray"; 186 scope = null; 187 intro = "declare -a"; 188 values = null; 189 }; 190 191 sameScopeDeclareEmptyArray = check { 192 name = "sameScopeDeclareEmptyArray"; 193 scope = null; 194 intro = "declare -a"; 195 values = "()"; 196 }; 197 198 sameScopeDeclareSingletonArray = check { 199 name = "sameScopeDeclareSingletonArray"; 200 scope = null; 201 intro = "declare -a"; 202 values = ''("hello!")''; 203 }; 204 205 previousScopeEmptyStringFails = testBuildFailure' { 206 name = "previousScopeEmptyStringFails"; 207 drv = check { 208 name = "previousScopeEmptyString"; 209 scope = "function"; 210 intro = null; 211 values = ""; 212 }; 213 expectedBuilderLogEntries = [ 214 "test failed" 215 ]; 216 }; 217 218 # Works because the variable isn't lexically scoped. 219 previousScopeEmptyArray = check { 220 name = "previousScopeEmptyArray"; 221 scope = "function"; 222 intro = null; 223 values = "()"; 224 }; 225 226 # Works because the variable isn't lexically scoped. 227 previousScopeSingletonArray = check { 228 name = "previousScopeSingletonArray"; 229 scope = "function"; 230 intro = null; 231 values = ''("hello!")''; 232 }; 233 234 previousScopeLocalUnsetArrayFails = testBuildFailure' { 235 name = "previousScopeLocalUnsetArrayFails"; 236 drv = check { 237 name = "previousScopeLocalUnsetArray"; 238 scope = "function"; 239 intro = "local -a"; 240 values = null; 241 }; 242 expectedBuilderLogEntries = [ 243 "test failed" 244 ]; 245 }; 246 247 previousScopeLocalEmptyArrayFails = testBuildFailure' { 248 name = "previousScopeLocalEmptyArrayFails"; 249 drv = check { 250 name = "previousScopeLocalEmptyArray"; 251 scope = "function"; 252 intro = "local -a"; 253 values = "()"; 254 }; 255 expectedBuilderLogEntries = [ 256 "test failed" 257 ]; 258 }; 259 260 previousScopeLocalSingletonArrayFails = testBuildFailure' { 261 name = "previousScopeLocalSingletonArrayFails"; 262 drv = check { 263 name = "previousScopeLocalSingletonArray"; 264 scope = "function"; 265 intro = "local -a"; 266 values = ''("hello!")''; 267 }; 268 expectedBuilderLogEntries = [ 269 "test failed" 270 ]; 271 }; 272 273 previousScopeLocalGlobalUnsetArray = check { 274 name = "previousScopeLocalGlobalUnsetArray"; 275 scope = "function"; 276 intro = "local -ag"; 277 values = null; 278 }; 279 280 previousScopeLocalGlobalEmptyArray = check { 281 name = "previousScopeLocalGlobalEmptyArray"; 282 scope = "function"; 283 intro = "local -ag"; 284 values = "()"; 285 }; 286 287 previousScopeLocalGlobalSingletonArray = check { 288 name = "previousScopeLocalGlobalSingletonArray"; 289 scope = "function"; 290 intro = "local -ag"; 291 values = ''("hello!")''; 292 }; 293 294 previousScopeDeclareUnsetArrayFails = testBuildFailure' { 295 name = "previousScopeDeclareUnsetArrayFails"; 296 drv = check { 297 name = "previousScopeDeclareUnsetArray"; 298 scope = "function"; 299 intro = "declare -a"; 300 values = null; 301 }; 302 expectedBuilderLogEntries = [ 303 "test failed" 304 ]; 305 }; 306 307 previousScopeDeclareEmptyArrayFails = testBuildFailure' { 308 name = "previousScopeDeclareEmptyArrayFails"; 309 drv = check { 310 name = "previousScopeDeclareEmptyArray"; 311 scope = "function"; 312 intro = "declare -a"; 313 values = "()"; 314 }; 315 expectedBuilderLogEntries = [ 316 "test failed" 317 ]; 318 }; 319 320 previousScopeDeclareSingletonArrayFails = testBuildFailure' { 321 name = "previousScopeDeclareSingletonArrayFails"; 322 drv = check { 323 name = "previousScopeDeclareSingletonArray"; 324 scope = "function"; 325 intro = "declare -a"; 326 values = ''("hello!")''; 327 }; 328 expectedBuilderLogEntries = [ 329 "test failed" 330 ]; 331 }; 332 333 previousScopeDeclareGlobalUnsetArray = check { 334 name = "previousScopeDeclareGlobalUnsetArray"; 335 scope = "function"; 336 intro = "declare -ag"; 337 values = null; 338 }; 339 340 previousScopeDeclareGlobalEmptyArray = check { 341 name = "previousScopeDeclareGlobalEmptyArray"; 342 scope = "function"; 343 intro = "declare -ag"; 344 values = "()"; 345 }; 346 347 previousScopeDeclareGlobalSingletonArray = check { 348 name = "previousScopeDeclareGlobalSingletonArray"; 349 scope = "function"; 350 intro = "declare -ag"; 351 values = ''("hello!")''; 352 }; 353}