mxsh 0.2.0

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

use mxsh::ShellBuilder;
use mxsh::embed::StdioConfig;
use mxsh::runtime::testing::{InMemoryRuntime, StringStdioOut};

fn run_script(script: &str) -> (i32, String, String) {
    let stdout = StringStdioOut::new();
    let stderr = StringStdioOut::new();
    let mut shell = ShellBuilder::new()
        .stdio(StdioConfig {
            stdout: stdout.fd(),
            stderr: stderr.fd(),
            ..StdioConfig::default()
        })
        .new_session()
        .expect("session should build");
    let mut runtime = InMemoryRuntime::new();

    let result = shell.run(&mut runtime, script);

    (result.status, stdout.collect(), stderr.collect())
}

#[test]
fn syntax_error_after_simple_command_does_not_execute_partial_line() {
    let (status, stdout, stderr) = run_script("echo should-not-run ( echo also-wrong )");

    assert_eq!(status, 2);
    assert_eq!(stdout, "");
    assert!(stderr.contains("unexpected token `('"));
}

#[test]
fn syntax_error_after_compound_command_does_not_execute_partial_line() {
    let (status, stdout, stderr) =
        run_script("if true; then echo should-not-run; fi echo also-wrong");

    assert_eq!(status, 2);
    assert_eq!(stdout, "");
    assert!(stderr.contains("unexpected token `echo'"));
}

#[test]
fn malformed_case_clause_does_not_execute_matched_body() {
    let (status, stdout, stderr) =
        run_script("case x in x) echo should-not-run; y) echo also-wrong;; esac");

    assert_eq!(status, 2);
    assert_eq!(stdout, "");
    assert!(stderr.contains("unexpected token `)'"));
}