//! Tests for setup hook functionality use std::fs; use tempfile::TempDir; // Tests for setup hook functionality - uses internal APIs use testscript_rs::run::{run_script, RunParams}; #[test] fn test_setup_hook_basic() { let temp_dir = TempDir::new().unwrap(); let script_path = temp_dir.path().join("setup_test.txt"); let script_content = r#"# Test that setup hook ran exists setup_was_here.txt exec cat setup_was_here.txt stdout "Setup ran successfully" -- other_file.txt -- existing content"#; fs::write(&script_path, script_content).unwrap(); // Create RunParams with setup hook let params = RunParams::new().setup(|env| { // Setup hook creates a file to prove it ran let setup_file = env.work_dir.join("setup_was_here.txt"); std::fs::write(&setup_file, "Setup ran successfully")?; Ok(()) }); let result = run_script(&script_path, ¶ms); assert!(result.is_ok(), "Setup hook test failed: {:?}", result); } #[test] fn test_setup_hook_compile_binary() { let temp_dir = TempDir::new().unwrap(); let script_path = temp_dir.path().join("binary_test.txt"); let script_content = r#"# Test that setup hook compiled a binary exists my-tool exec ./my-tool --help stdout "Mock CLI Tool""#; fs::write(&script_path, script_content).unwrap(); // Create RunParams with setup hook that "compiles" a mock binary let params = RunParams::new().setup(|env| { // Create a mock binary script for testing let binary_path = env.work_dir.join("my-tool"); let mock_binary = r#"#!/bin/sh if [ "$1" = "--help" ]; then echo "Mock CLI Tool" echo "Usage: my-tool [options]" else echo "Hello from my-tool" fi"#; std::fs::write(&binary_path, mock_binary)?; // Make it executable (on Unix systems) #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; let mut perms = std::fs::metadata(&binary_path)?.permissions(); perms.set_mode(0o755); std::fs::set_permissions(&binary_path, perms)?; } Ok(()) }); let result = run_script(&script_path, ¶ms); // This might fail on Windows or if shell scripting isn't available if result.is_err() { println!( "Binary compilation test failed (expected on some systems): {:?}", result ); } else { println!("Setup hook binary test passed!"); } } #[test] fn test_setup_hook_environment() { let temp_dir = TempDir::new().unwrap(); let script_path = temp_dir.path().join("env_test.txt"); // Use sh -c to allow shell variable expansion let script_content = if cfg!(windows) { r#"# Test setup hook can modify environment (Windows) exec cmd /c "echo Value: %TEST_FROM_SETUP%" stdout "Value: hello_from_setup""# } else { r#"# Test setup hook can modify environment (Unix) exec sh -c "echo Value: $TEST_FROM_SETUP" stdout "Value: hello_from_setup"# }; fs::write(&script_path, script_content).unwrap(); // Create RunParams with setup hook that sets an environment variable let params = RunParams::new().setup(|env| { // Now we can modify the environment directly in the setup hook env.set_env_var("TEST_FROM_SETUP", "hello_from_setup"); Ok(()) }); let result = run_script(&script_path, ¶ms); assert!( result.is_ok(), "Environment setup test should pass: {:?}", result ); } #[test] fn test_setup_hook_multiple_env_vars() { let temp_dir = TempDir::new().unwrap(); let script_path = temp_dir.path().join("multi_env_test.txt"); // Use sh -c to allow shell variable expansion let script_content = if cfg!(windows) { r#"# Test setup hook can set multiple environment variables (Windows) exec cmd /c "echo FOO=%FOO% BAR=%BAR% BAZ=%BAZ%" stdout "FOO=value1 BAR=value2 BAZ=value3""# } else { r#"# Test setup hook can set multiple environment variables (Unix) exec sh -c "echo FOO=$FOO BAR=$BAR BAZ=$BAZ" stdout "FOO=value1 BAR=value2 BAZ=value3"# }; fs::write(&script_path, script_content).unwrap(); // Create RunParams with setup hook that sets multiple environment variables let params = RunParams::new().setup(|env| { env.set_env_var("FOO", "value1"); env.set_env_var("BAR", "value2"); env.set_env_var("BAZ", "value3"); Ok(()) }); let result = run_script(&script_path, ¶ms); assert!( result.is_ok(), "Multiple environment variables test should pass: {:?}", result ); } #[test] fn test_setup_hook_failure() { let temp_dir = TempDir::new().unwrap(); let script_path = temp_dir.path().join("fail_test.txt"); let script_content = r#"# This should never run because setup fails exec echo "Should not execute""#; fs::write(&script_path, script_content).unwrap(); // Create RunParams with failing setup hook let params = RunParams::new().setup(|_env| { Err(testscript_rs::Error::Generic( "Setup deliberately failed".to_string(), )) }); let result = run_script(&script_path, ¶ms); assert!(result.is_err(), "Setup hook should have failed the test"); assert!(result .unwrap_err() .to_string() .contains("Setup deliberately failed")); } #[test] fn test_setup_env_vars_presence_and_absence() { let temp_dir = TempDir::new().unwrap(); let script_path = temp_dir.path().join("env_presence_test.txt"); // Test that verifies: // 1. Variables set in setup ARE available in the test // 2. Variables NOT set in setup are NOT available in the test let script_content = if cfg!(windows) { r#"# Test environment variable presence and absence (Windows) # Check that SET_VAR is available using printenv (no shell needed) exec cmd /c set SET_VAR stdout "SET_VAR=value_from_setup" # Also verify with shell expansion exec cmd /c "echo SET_VAR=%SET_VAR%" stdout "SET_VAR=value_from_setup" # Check that UNSET_VAR is not available ! exec cmd /c set UNSET_VAR"# } else { r#"# Test environment variable presence and absence (Unix) # Check that SET_VAR is available using printenv (no shell needed) exec printenv SET_VAR stdout "value_from_setup" # Also verify with shell expansion exec sh -c "echo SET_VAR=$SET_VAR" stdout "SET_VAR=value_from_setup" # Check that UNSET_VAR is not available ! exec printenv UNSET_VAR"# }; fs::write(&script_path, script_content).unwrap(); // Create RunParams with setup hook that only sets SET_VAR, not UNSET_VAR let params = RunParams::new().setup(|env| { env.set_env_var("SET_VAR", "value_from_setup"); // Deliberately NOT setting UNSET_VAR to verify it's not available Ok(()) }); let result = run_script(&script_path, ¶ms); assert!( result.is_ok(), "Environment presence/absence test should pass: {:?}", result ); } #[test] fn test_env_command_prints_all_vars() { let temp_dir = TempDir::new().unwrap(); let script_path = temp_dir.path().join("env_print_test.txt"); // Test that 'env' without args prints all environment variables let script_content = r#"# Test env command prints all variables env VAR1=value1 env VAR2=value2 # The env command should be callable and set variables # (printing is done to stdout which we can't easily test here, # but we verify the vars are set by using them) exec sh -c "echo $VAR1" stdout "value1" exec sh -c "echo $VAR2" stdout "value2" "#; fs::write(&script_path, script_content).unwrap(); let params = RunParams::new().setup(|env| { env.set_env_var("SETUP_VAR", "from_setup"); Ok(()) }); let result = run_script(&script_path, ¶ms); assert!( result.is_ok(), "Env command test should pass: {:?}", result ); }