bare-script 0.1.1

The type-safe scripting authority for Rust. A framework for building robust shell commands and automation with 'Parse, don't validate' philosophy.
Documentation
//! Async integration tests for bare-script.

#![allow(unused_imports)]

use bare_script::proc::CommandBuilder;
use thiserror::Error as _;

/// Test basic async command execution.
#[tokio::test]
async fn test_async_basic_execute() {
    #[cfg(windows)]
    let output = {
        CommandBuilder::new("cmd")
            .args(["/C", "echo hello"])
            .capture_output()
            .execute()
            .await
    };

    #[cfg(not(windows))]
    let output = {
        CommandBuilder::new("echo")
            .arg("hello")
            .capture_output()
            .execute()
            .await
    };

    assert!(output.is_ok());
    let output = output.unwrap();
    assert!(output.success());
}

/// Test async argument passing.
#[tokio::test]
async fn test_async_args() {
    #[cfg(windows)]
    let output = {
        CommandBuilder::new("cmd")
            .args(["/C", "echo hello world"])
            .capture_output()
            .execute()
            .await
    };

    #[cfg(not(windows))]
    let output = {
        CommandBuilder::new("echo")
            .arg("hello")
            .arg("world")
            .capture_output()
            .execute()
            .await
    };

    assert!(output.is_ok());
    let output = output.unwrap();
    assert!(output.stdout_str().contains("hello"));
}

/// Test async environment variables.
#[tokio::test]
async fn test_async_env() {
    #[cfg(windows)]
    let output = {
        CommandBuilder::new("cmd")
            .args(["/C", "echo %ASYNC_TEST_VAR%"])
            .env("ASYNC_TEST_VAR", "async_test_value")
            .capture_output()
            .execute()
            .await
    };

    #[cfg(not(windows))]
    let output = {
        CommandBuilder::new("sh")
            .args(["-c", "echo $ASYNC_TEST_VAR"])
            .env("ASYNC_TEST_VAR", "async_test_value")
            .capture_output()
            .execute()
            .await
    };

    assert!(output.is_ok());
    let output = output.unwrap();
    assert!(output.stdout_str().contains("async_test_value"));
}

/// Test async working directory.
#[tokio::test]
async fn test_async_current_dir() {
    use std::env;

    let current_dir = env::current_dir().expect("Failed to get current dir");

    #[cfg(windows)]
    let output = {
        CommandBuilder::new("cmd")
            .args(["/C", "cd"])
            .current_dir(&current_dir)
            .capture_output()
            .execute()
            .await
    };

    #[cfg(not(windows))]
    let output = {
        CommandBuilder::new("pwd")
            .current_dir(&current_dir)
            .capture_output()
            .execute()
            .await
    };

    assert!(output.is_ok());
}

/// Test async timeout functionality.
#[tokio::test]
async fn test_async_timeout() {
    use std::time::Duration;

    #[cfg(windows)]
    let result = {
        CommandBuilder::new("cmd")
            .args(["/C", "ping -n 10 127.0.0.1"])
            .capture_output()
            .execute_with_timeout(Duration::from_millis(100))
            .await
    };

    #[cfg(not(windows))]
    let result = {
        CommandBuilder::new("sleep")
            .arg("10")
            .capture_output()
            .execute_with_timeout(Duration::from_millis(100))
            .await
    };

    // Should timeout
    assert!(result.is_err());
    let err = result.unwrap_err();
    assert!(matches!(err, bare_script::ScriptError::Timeout(_)));
}

/// Test async exit code handling.
#[tokio::test]
async fn test_async_exit_code() {
    #[cfg(windows)]
    let output = {
        CommandBuilder::new("cmd")
            .args(["/C", "exit 42"])
            .capture_output()
            .execute()
            .await
    };

    #[cfg(not(windows))]
    let output = {
        CommandBuilder::new("sh")
            .args(["-c", "exit 42"])
            .capture_output()
            .execute()
            .await
    };

    assert!(output.is_ok());
    let output = output.unwrap();
    assert!(!output.success());
    assert_eq!(output.code(), Some(42));
}

/// Test kill_on_drop functionality.
#[tokio::test]
async fn test_kill_on_drop() {
    use std::time::Duration;
    use tokio::time::sleep;

    #[cfg(windows)]
    let result = {
        CommandBuilder::new("cmd")
            .args(["/C", "ping -n 30 127.0.0.1"])
            .kill_on_drop(true)
            .capture_output()
            .spawn()
            .await
    };

    #[cfg(not(windows))]
    let result = {
        CommandBuilder::new("sleep")
            .arg("30")
            .kill_on_drop(true)
            .capture_output()
            .spawn()
            .await
    };

    assert!(result.is_ok());
    let child = result.unwrap();

    // Wait a bit to ensure process is running
    sleep(Duration::from_millis(50)).await;

    // Kill the child by dropping it
    drop(child);

    // Give some time for the process to be killed
    sleep(Duration::from_millis(50)).await;
}