From 185a0b1a8c727aa76d759d40a7f4a422d47923bd Mon Sep 17 00:00:00 2001 From: Mykhailo Chalyi Date: Sat, 28 Mar 2026 09:23:06 +0000 Subject: [PATCH] test(interpreter): add regression tests for issue #875 Add tests verifying associative array key expansion (${!assoc[@]}) works correctly inside process substitution nested in command substitution. The bug was already fixed by prior commits but lacked a targeted regression test. Closes #875 --- crates/bashkit/tests/issue_875_test.rs | 86 ++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 crates/bashkit/tests/issue_875_test.rs diff --git a/crates/bashkit/tests/issue_875_test.rs b/crates/bashkit/tests/issue_875_test.rs new file mode 100644 index 00000000..8baf3908 --- /dev/null +++ b/crates/bashkit/tests/issue_875_test.rs @@ -0,0 +1,86 @@ +//! Test for issue #875: Associative array key expansion (`${!assoc[@]}`) +//! returns empty when used inside a process substitution nested inside a +//! command substitution. + +use bashkit::Bash; + +#[tokio::test] +async fn assoc_keys_visible_in_nested_procsub_cmdsub() { + let mut bash = Bash::new(); + let result = bash + .exec( + r#" +myfunc() { + declare -A m=() + m["a"]="1" + m["b"]="2" + + # Process substitution inside command substitution + result="$(while IFS= read -r k; do echo "$k"; done < <(printf '%s\n' "${!m[@]}"))" + echo "nested result: [$result]" +} +myfunc +"#, + ) + .await + .unwrap(); + // Keys should be visible (order may vary since assoc arrays are unordered) + assert!( + result.stdout.contains("a") && result.stdout.contains("b"), + "expected keys 'a' and 'b' in nested result, got: {}", + result.stdout + ); + assert!( + !result.stdout.contains("nested result: []"), + "nested result should not be empty, got: {}", + result.stdout + ); +} + +#[tokio::test] +async fn assoc_keys_direct_expansion() { + let mut bash = Bash::new(); + let result = bash + .exec( + r#" +myfunc() { + declare -A m=() + m["x"]="10" + m["y"]="20" + echo "direct keys: ${!m[@]}" +} +myfunc +"#, + ) + .await + .unwrap(); + assert!( + result.stdout.contains("x") && result.stdout.contains("y"), + "expected keys 'x' and 'y', got: {}", + result.stdout + ); +} + +#[tokio::test] +async fn assoc_keys_in_procsub_alone() { + let mut bash = Bash::new(); + let result = bash + .exec( + r#" +myfunc() { + declare -A m=() + m["p"]="1" + m["q"]="2" + while IFS= read -r k; do echo "procsub: $k"; done < <(printf '%s\n' "${!m[@]}") +} +myfunc +"#, + ) + .await + .unwrap(); + assert!( + result.stdout.contains("procsub: p") || result.stdout.contains("procsub: q"), + "expected keys in procsub output, got: {}", + result.stdout + ); +}