mxsh 0.1.0

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

use mxsh::ShellBuilder;
use mxsh::ast::{Program, Spanned};
use mxsh::parser::{ParseDiagnosticKind, ParseOptions};
use mxsh::policy::ShellLanguage;
use mxsh::runtime::testing::{InMemoryRuntime, StringStdioOut};

#[test]
fn parse_program_with_language_rejects_function_definitions() {
    let err = Program::parse_with(
        "f() { :; }\n",
        &ParseOptions::new().function_definitions_enabled(false),
    )
    .expect_err("function definitions should be rejected");
    assert_eq!(err.code, "parse.syntax");
}

#[test]
fn parse_with_collects_structured_warnings() {
    let parsed = Program::parse_with(
        "echo `myfunc() { :; }`\n",
        &ParseOptions::new().function_definitions_enabled(false),
    )
    .expect("outer program should parse");

    assert!(
        parsed
            .diagnostics()
            .iter()
            .any(|diagnostic| diagnostic.kind == ParseDiagnosticKind::Warning
                && diagnostic.code == "parse.warning")
    );
}

#[test]
fn parsed_program_reports_spans() {
    let program = Program::parse("echo hello\n").expect("program should parse");
    let span = program.span();

    assert_eq!(span.begin.line, 1);
    assert_eq!(span.begin.column, 1);
    assert_eq!(span.end.line, 1);
    assert!(span.end.column > span.begin.column);
}

#[test]
fn config_language_disables_alias_expansion_in_new_sessions() {
    let stdout = StringStdioOut::new();
    let mut session = ShellBuilder::new()
        .language(ShellLanguage::new().with_alias_expansion_enabled(false))
        .alias("ll", "echo aliased")
        .stdio(mxsh::embed::StdioConfig {
            stdout: stdout.fd(),
            ..mxsh::embed::StdioConfig::default()
        })
        .new_session()
        .expect("session should build");
    let mut runtime = InMemoryRuntime::new();

    let result = session.run(&mut runtime, "ll");

    assert!(!session.language().alias_expansion_enabled());
    assert_eq!(result.status, 127);
    assert_eq!(stdout.collect(), "");
}

#[test]
fn config_language_disables_function_definitions_in_new_sessions() {
    let mut session = ShellBuilder::new()
        .language(ShellLanguage::new().with_function_definitions_enabled(false))
        .new_session()
        .expect("session should build");
    let mut runtime = InMemoryRuntime::new();

    let result = session.run(&mut runtime, "f() { :; }");

    assert!(!session.language().function_definitions_enabled());
    assert_eq!(result.status, 2);
    assert!(session.function("f").is_none());
}