mxsh 0.2.0

Embeddable POSIX-style shell parser and runtime
Documentation
#![cfg(all(
    feature = "embed",
    feature = "frontend",
    feature = "test-support",
    feature = "unix-runtime"
))]

mod support;

use std::fs;

use mxsh::ShellBuilder;
use mxsh::embed::StdioConfig;
use mxsh::policy::{ShellIdentity, VariableAttributes};
use mxsh::runtime::testing::{InMemoryRuntime, StringStdioIn, StringStdioOut};

#[test]
fn custom_shell_identity_sets_shell_name_and_dollar_zero() {
    let stdout = StringStdioOut::new();
    let mut shell = ShellBuilder::new()
        .identity(ShellIdentity::named("toysh"))
        .stdio(StdioConfig {
            stdout: stdout.fd(),
            ..StdioConfig::default()
        })
        .new_session()
        .expect("session should build");
    let mut runtime = InMemoryRuntime::new();

    let result = shell.run(&mut runtime, "echo $0");

    assert_eq!(result.status, 0);
    assert_eq!(shell.shell_name(), "toysh");
    assert_eq!(shell.identity().history_env_var(), "TOYSH_HISTORY_FILE");
    assert_eq!(stdout.collect(), "toysh\n");
}

#[test]
fn custom_shell_identity_controls_history_env_lookup() {
    let input = StringStdioIn::new("echo hi\nexit\n");
    let stdout = StringStdioOut::new();
    let history_path = support::temp_path("toysh-history");
    let mut shell = ShellBuilder::new()
        .identity(ShellIdentity::named("toysh"))
        .interactive(true)
        .clear_inherited_env()
        .env(
            "HOME",
            std::env::temp_dir().display().to_string(),
            VariableAttributes::empty(),
        )
        .env(
            "TOYSH_HISTORY_FILE",
            history_path.display().to_string(),
            VariableAttributes::empty(),
        )
        .stdio(StdioConfig {
            stdin: input.fd(),
            stdout: stdout.fd(),
            stderr: stdout.fd(),
        })
        .new_session()
        .expect("session should build");
    let mut runtime = InMemoryRuntime::new();

    shell.initialize(&mut runtime);
    let result = shell
        .run_interactive(&mut runtime)
        .expect("interactive shell should succeed");
    input.join();
    let _ = stdout.collect();

    assert_eq!(result.exit_code, Some(0));
    let history = fs::read_to_string(&history_path).expect("history file should exist");
    assert!(history.contains("echo hi\n"));
    assert!(history.contains("exit\n"));
    let _ = fs::remove_file(history_path);
}