Files
endorphin-aster-vm/crates/cli/tests/execute.rs
T
codex-bot aa3257bfe6
Verify databases and deploy Aster VM / verify-and-deploy (push) Successful in 7m56s
feat: connect source compilation and VM execution
2026-10-19 14:50:37 +08:00

137 lines
4.3 KiB
Rust

use std::io::Write;
use std::process::{Command, Output, Stdio};
fn stdin_command(arguments: &[&str], source: &[u8]) -> Output {
let mut child = Command::new(env!("CARGO_BIN_EXE_cli"))
.args(arguments)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
child.stdin.take().unwrap().write_all(source).unwrap();
child.wait_with_output().unwrap()
}
#[test]
fn run_executes_real_endor_files_and_prints_entry_results() {
for (file, expected) in [
("hello.endor", "你好,Endor 🌱\n"),
("calls.endor", "函数调用已接通\n"),
("shadowing.endor", "局部名称优先\n"),
("number.endor", "-123456789012345678901234567890.00100\n"),
] {
let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../compiler/examples")
.join(file);
let output = Command::new(env!("CARGO_BIN_EXE_cli"))
.arg("run")
.arg(path)
.output()
.unwrap();
assert!(
output.status.success(),
"{}",
String::from_utf8_lossy(&output.stderr)
);
assert_eq!(String::from_utf8(output.stdout).unwrap(), expected);
assert!(output.stderr.is_empty());
}
}
#[test]
fn eval_and_run_read_stdin_and_support_explicit_entry_names() {
let output = stdin_command(&["eval", "-"], "\"表达式🌱\"".as_bytes());
assert!(
output.status.success(),
"{}",
String::from_utf8_lossy(&output.stderr)
);
assert_eq!(String::from_utf8(output.stdout).unwrap(), "表达式🌱\n");
let output = stdin_command(
&["run", "--entry", "greet", "-"],
b"function greet(): String { return \"ok\" }",
);
assert!(
output.status.success(),
"{}",
String::from_utf8_lossy(&output.stderr)
);
assert_eq!(String::from_utf8(output.stdout).unwrap(), "ok\n");
let path =
std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../compiler/examples/literal.endor");
let output = Command::new(env!("CARGO_BIN_EXE_cli"))
.arg("eval")
.arg(path)
.output()
.unwrap();
assert!(output.status.success());
assert_eq!(
String::from_utf8(output.stdout).unwrap(),
"表达式 → 字节码 → VM\n"
);
}
#[test]
fn execution_errors_fail_without_success_output_and_report_their_stage() {
for (arguments, source, expected) in [
(
vec!["run", "-"],
"function main(): T {\n return missing\n}",
"<stdin>:2:10: undefined name: missing",
),
(
vec!["run", "-"],
"function main(): T { return f() } function f(x: T): T { return x }",
"positional arguments",
),
(
vec!["run", "-"],
"function other(): T { return 1 }",
"entry function not found: main",
),
(
vec!["eval", "-"],
"1 + 2",
"arithmetic bytecode is not implemented",
),
(vec!["eval", "-"], "1()", "does not support call"),
(
vec!["run", "-"],
"function main(): T { return ) }",
"expected",
),
] {
let output = stdin_command(&arguments, source.as_bytes());
assert!(!output.status.success());
assert!(output.stdout.is_empty());
let error = String::from_utf8(output.stderr).unwrap();
assert!(error.contains(expected), "{error}");
if expected == "positional arguments" {
assert!(error.contains("at main (<stdin>:1, code unit"));
}
}
let output = stdin_command(&["eval", "-"], &[0xff]);
assert!(!output.status.success());
assert!(
String::from_utf8(output.stderr)
.unwrap()
.contains("invalid UTF-8")
);
for arguments in [
vec!["run"],
vec!["run", "--entry"],
vec!["run", "--unknown", "-"],
vec!["eval"],
vec!["eval", "-", "extra"],
] {
let output = Command::new(env!("CARGO_BIN_EXE_cli"))
.args(arguments)
.output()
.unwrap();
assert!(!output.status.success());
assert!(output.stdout.is_empty());
assert!(String::from_utf8(output.stderr).unwrap().contains("Usage:"));
}
}