use tempfile::TempDir;
use tmuxrs::session::SessionManager;
use tmuxrs::tmux::TmuxCommand;
struct ShellTestHelper {
temp_dir: TempDir,
config_dir: std::path::PathBuf,
session_name: String,
}
impl ShellTestHelper {
fn new(test_name: &str) -> Self {
let temp_dir = TempDir::new().unwrap();
let config_dir = temp_dir.path().join(".config").join("tmuxrs");
std::fs::create_dir_all(&config_dir).unwrap();
let session_name = format!("shell-test-{test_name}");
Self {
temp_dir,
config_dir,
session_name,
}
}
#[allow(dead_code)]
fn setup_shell_config(&self) -> std::path::PathBuf {
let shell_config_dir = self.temp_dir.path().join("shell_config");
std::fs::create_dir_all(&shell_config_dir).unwrap();
let bashrc_path = shell_config_dir.join(".bashrc");
let bashrc_content = r#"
# Test shell configuration
export SHELL_TEST_VAR="shell_initialized"
export CUSTOM_PATH="/test/bin:$PATH"
# Test alias
alias test_alias='echo "alias works"'
# Test function
test_function() {
echo "function works: $1"
}
# Custom prompt to verify interactive shell
export PS1="[TEST_SHELL] $ "
# Mark that this config was loaded
export BASHRC_LOADED="yes"
"#;
std::fs::write(&bashrc_path, bashrc_content).unwrap();
shell_config_dir
}
fn create_tmuxrs_config(&self, windows_config: &str) {
let config_file = self.config_dir.join(format!("{}.yml", self.session_name));
let yaml_content = format!(
r#"
name: {}
root: {}
windows:
{}
"#,
self.session_name,
self.temp_dir.path().display(),
windows_config
);
std::fs::write(&config_file, yaml_content).unwrap();
}
fn start_session_detached(&self) -> Result<(), Box<dyn std::error::Error>> {
let session_manager = SessionManager::new();
session_manager.start_session_with_options(
Some(&self.session_name),
Some(&self.config_dir),
false, false, )?;
Ok(())
}
fn send_command_and_capture(
&self,
window: &str,
command: &str,
) -> Result<String, Box<dyn std::error::Error>> {
TmuxCommand::send_keys(&self.session_name, window, command)?;
std::thread::sleep(std::time::Duration::from_millis(500));
let output = std::process::Command::new("tmux")
.args([
"capture-pane",
"-t",
&format!("{}:{}", self.session_name, window),
"-p",
])
.output()?;
Ok(String::from_utf8_lossy(&output.stdout).to_string())
}
#[allow(dead_code)]
fn verify_output_contains(
&self,
window: &str,
expected: &str,
) -> Result<bool, Box<dyn std::error::Error>> {
let output = self.send_command_and_capture(window, "")?; Ok(output.contains(expected))
}
}
impl Drop for ShellTestHelper {
fn drop(&mut self) {
let _ = TmuxCommand::kill_session(&self.session_name);
}
}
#[test]
fn test_shell_initialization_files_executed() {
if std::env::var("CI").is_ok() {
return;
}
let helper = ShellTestHelper::new("init-files");
helper.create_tmuxrs_config(
r#"
- test_window: bash"#,
);
assert!(helper.start_session_detached().is_ok());
let output = helper
.send_command_and_capture("test_window", "echo $HOME")
.unwrap();
assert!(
!output.trim().is_empty(),
"HOME should be available from shell initialization"
);
let output = helper
.send_command_and_capture("test_window", "echo $-")
.unwrap();
assert!(
output.contains("i") || !output.trim().is_empty(),
"Shell should be interactive or responsive"
);
}
#[test]
fn test_interactive_shell_features() {
if std::env::var("CI").is_ok() {
return;
}
let helper = ShellTestHelper::new("interactive");
helper.create_tmuxrs_config(
r#"
- shell_window: bash"#,
);
assert!(helper.start_session_detached().is_ok());
helper
.send_command_and_capture("shell_window", "alias test_alias='echo alias_works'")
.unwrap();
let output = helper
.send_command_and_capture("shell_window", "test_alias")
.unwrap();
assert!(output.contains("alias_works"), "Shell aliases should work");
helper
.send_command_and_capture("shell_window", "test_func() { echo 'func_works'; }")
.unwrap();
let output = helper
.send_command_and_capture("shell_window", "test_func")
.unwrap();
assert!(output.contains("func_works"), "Shell functions should work");
}
#[test]
fn test_environment_inheritance() {
if std::env::var("CI").is_ok() {
return;
}
let helper = ShellTestHelper::new("environment");
helper.create_tmuxrs_config(
r#"
- env_window: echo "Environment test window""#,
);
assert!(helper.start_session_detached().is_ok());
let output = helper
.send_command_and_capture("env_window", "export TEST_VAR='test_value'; echo $TEST_VAR")
.unwrap();
assert!(
output.contains("test_value"),
"Should be able to set and use environment variables"
);
let output = helper
.send_command_and_capture("env_window", "echo 'shell_responsive'")
.unwrap();
assert!(
output.contains("shell_responsive"),
"Shell should be responsive to commands"
);
}
#[test]
fn test_shell_features_in_split_panes() {
if std::env::var("CI").is_ok() {
return;
}
let helper = ShellTestHelper::new("split-panes");
helper.create_tmuxrs_config(
r#"
- split_test:
layout: main-vertical
panes:
- "echo 'pane1'; bash"
- "echo 'pane2'; bash"
"#,
);
assert!(helper.start_session_detached().is_ok());
let session_exists = TmuxCommand::session_exists(&helper.session_name).unwrap();
assert!(
session_exists,
"Session with split panes should be created successfully"
);
}
#[test]
fn test_shell_command_execution() {
if std::env::var("CI").is_ok() {
return;
}
let helper = ShellTestHelper::new("commands");
helper.create_tmuxrs_config(
r#"
- cmd_window: echo "initial command executed""#,
);
assert!(helper.start_session_detached().is_ok());
std::thread::sleep(std::time::Duration::from_secs(1));
let output = helper.send_command_and_capture("cmd_window", "").unwrap();
assert!(
output.contains("initial command executed"),
"Initial command should execute"
);
let output = helper
.send_command_and_capture("cmd_window", "echo 'additional command'")
.unwrap();
assert!(
output.contains("additional command"),
"Additional commands should work"
);
let output = helper
.send_command_and_capture("cmd_window", "echo 'test' | grep 'test'")
.unwrap();
assert!(
output.contains("test"),
"Complex shell commands should work"
);
}
#[test]
fn test_no_shell_config_works_normally() {
if std::env::var("CI").is_ok() {
return;
}
let helper = ShellTestHelper::new("normal");
helper.create_tmuxrs_config(
r#"
- normal_window: echo "normal session"
- shell_window: bash"#,
);
match helper.start_session_detached() {
Ok(_) => (),
Err(e) => panic!("Failed to start session: {e}"),
}
let output = helper
.send_command_and_capture("normal_window", "echo 'test normal'")
.unwrap();
assert!(
output.contains("test normal"),
"Normal commands should work without custom config"
);
let output = helper
.send_command_and_capture("shell_window", "ls /")
.unwrap();
assert!(
!output.trim().is_empty(),
"Standard shell commands should work"
);
}
#[test]
fn test_shell_state_independence() {
if std::env::var("CI").is_ok() {
return;
}
let helper = ShellTestHelper::new("independence");
helper.create_tmuxrs_config(
r#"
- window1: bash
- window2: bash"#,
);
assert!(helper.start_session_detached().is_ok());
helper
.send_command_and_capture("window1", "export TEST_VAR='window1_value'")
.unwrap();
let output = helper
.send_command_and_capture("window2", "echo $TEST_VAR")
.unwrap();
assert!(
!output.contains("window1_value"),
"Windows should have independent shell states"
);
helper
.send_command_and_capture("window2", "export TEST_VAR='window2_value'")
.unwrap();
let output = helper
.send_command_and_capture("window1", "echo $TEST_VAR")
.unwrap();
assert!(
output.contains("window1_value"),
"First window should maintain its state"
);
}