#![allow(unused_imports)]
use super::helpers::AftProcess;
use serde_json::json;
use serde_json::Value;
use std::time::{Duration, Instant};
#[test]
#[cfg(target_os = "windows")]
fn windows_bash_echo_completes_quickly() {
let mut aft = AftProcess::spawn();
let started = Instant::now();
let frames = aft.send_until(
r#"{"id":"win-bash-1","method":"bash","params":{"command":"Write-Output hello"}}"#,
|value| value["id"] == "win-bash-1",
);
let elapsed = started.elapsed();
let response = frames
.iter()
.find(|frame| frame["id"] == "win-bash-1")
.expect("expected response for win-bash-1");
assert_eq!(response["success"], true, "bash command should succeed");
assert!(
elapsed < Duration::from_secs(15),
"trivial echo took {}ms — investigate Windows bash spawn overhead",
elapsed.as_millis()
);
}
#[test]
#[cfg(target_os = "windows")]
fn windows_bash_handles_powershell_pipe() {
let mut aft = AftProcess::spawn();
let frames = aft.send_until(
r#"{"id":"win-pipe","method":"bash","params":{"command":"Write-Output hello | Select-String hello"}}"#,
|value| value["id"] == "win-pipe",
);
let response = frames
.iter()
.find(|frame| frame["id"] == "win-pipe")
.expect("expected response for win-pipe");
assert_eq!(response["success"], true);
let output = response["data"]["output"].as_str().unwrap_or_default();
assert!(
output.contains("hello"),
"expected pipe output to contain 'hello', got: {output}"
);
}
#[test]
#[ignore]
#[cfg(target_os = "windows")]
fn windows_bash_30s_sleep_completes_under_transport_budget() {
let mut aft = AftProcess::spawn();
let started = Instant::now();
let frames = aft.send_until(
r#"{"id":"win-sleep-30","method":"bash","params":{"command":"Start-Sleep -Seconds 30; Write-Output done","timeout":60000}}"#,
|value| value["id"] == "win-sleep-30",
);
let elapsed = started.elapsed();
let response = frames
.iter()
.find(|frame| frame["id"] == "win-sleep-30")
.expect("expected response for win-sleep-30");
assert_eq!(
response["success"], true,
"30s sleep with 60s user-timeout must complete (transport budget = 65s)"
);
assert!(
elapsed < Duration::from_secs(50),
"30s sleep took {}s round-trip — Windows spawn overhead is dangerous",
elapsed.as_secs()
);
}
#[test]
#[cfg(target_os = "windows")]
fn windows_bash_blocks_path_env_case_insensitively() {
let mut aft = AftProcess::spawn();
let frames = aft.send_until(
r#"{"id":"win-env-block","method":"bash","params":{"command":"Write-Output ok","env":{"path":"C:\\evil"}}}"#,
|value| value["id"] == "win-env-block",
);
let response = frames
.iter()
.find(|frame| frame["id"] == "win-env-block")
.expect("expected response for win-env-block");
if response["success"] == true {
let stringified = response.to_string();
assert!(
stringified.to_lowercase().contains("path")
|| stringified.to_lowercase().contains("blocked"),
"expected blocked env var to surface in response: {stringified}"
);
} else {
let message = response["message"].as_str().unwrap_or_default();
assert!(
message.to_lowercase().contains("path") || message.to_lowercase().contains("blocked"),
"expected error message to mention blocked env var, got: {message}"
);
}
}
#[test]
#[cfg(target_os = "windows")]
fn windows_cmd_background_wrapper_allows_bang_in_path() {
let parent = tempfile::tempdir().unwrap();
let project = parent.path().join("project!bang");
std::fs::create_dir_all(&project).unwrap();
let storage = parent.path().join("storage!bang");
std::fs::create_dir_all(&storage).unwrap();
let mut aft = AftProcess::spawn();
let cfg = aft.send(
&json!({
"id":"cfg-win-bang",
"command":"configure",
"project_root": project,
"storage_dir": storage,
"experimental_bash_background": true,
})
.to_string(),
);
assert_eq!(cfg["success"], true, "configure failed: {cfg:?}");
let spawned = aft.send(
&json!({
"id":"spawn-win-bang",
"command":"bash",
"params":{"command":"cmd /D /C exit /B 0","background":true}
})
.to_string(),
);
assert_eq!(spawned["success"], true, "spawn failed: {spawned:?}");
let task_id = spawned["task_id"].as_str().unwrap();
let started = Instant::now();
loop {
let status = aft.send(
&json!({
"id":"status-win-bang",
"command":"bash_status",
"params":{"task_id":task_id}
})
.to_string(),
);
if status["status"] == "completed" {
assert_eq!(status["exit_code"], 0);
break;
}
assert!(
started.elapsed() < Duration::from_secs(10),
"timed out: {status:?}"
);
std::thread::sleep(Duration::from_millis(100));
}
assert!(aft.shutdown().success());
}
#[test]
#[cfg(not(target_os = "windows"))]
fn windows_bash_tests_skipped_on_non_windows() {
}