diff --git a/cli/src/main.rs b/cli/src/main.rs index abb0418a764..ffe95be38e4 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -411,15 +411,22 @@ fn evaluate_expr( let result = script.evaluate(context); if let Err(err) = context.run_jobs() { printer.print(uncaught_job_error(&err)); + return Err(eyre!("execution failed")); } result }; match result { Ok(v) => printer.print(format!("{}\n", v.display())), - Err(ref v) => printer.print(uncaught_error(v)), + Err(v) => { + printer.print(uncaught_error(&v)); + return Err(eyre!("execution failed")); + } } } - Err(ref v) => printer.print(uncaught_error(v)), + Err(v) => { + printer.print(uncaught_error(&v)); + return Err(eyre!("parsing failed")); + } } } @@ -503,7 +510,10 @@ fn evaluate_file( println!("{}", v.display()); } } - Err(v) => printer.print(uncaught_error(&v)), + Err(v) => { + printer.print(uncaught_error(&v)); + return Err(eyre!("execution failed")); + } } Ok(()) diff --git a/cli/tests/exit_code.rs b/cli/tests/exit_code.rs new file mode 100644 index 00000000000..f853f600e92 --- /dev/null +++ b/cli/tests/exit_code.rs @@ -0,0 +1,66 @@ +#![allow(missing_docs)] + +use std::fs; +use std::io::Write; +use std::process::{Command, Stdio}; +use std::time::{SystemTime, UNIX_EPOCH}; + +fn boa_bin() -> &'static str { + env!("CARGO_BIN_EXE_boa") +} + +#[test] +fn stdin_uncaught_error_exits_non_zero() { + let mut child = Command::new(boa_bin()) + .stdin(Stdio::piped()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .expect("boa binary should build"); + + child + .stdin + .as_mut() + .expect("stdin should be piped") + .write_all(b"throw Error('nooo')") + .expect("stdin write should succeed"); + + let status = child.wait().expect("boa should exit"); + assert!(!status.success(), "expected non-zero exit for uncaught stdin error"); +} + +#[test] +fn expression_uncaught_error_exits_non_zero() { + let status = Command::new(boa_bin()) + .args(["-e", "throw Error('nooo')"]) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .expect("boa should run"); + + assert!(!status.success(), "expected non-zero exit for uncaught -e error"); +} + +#[test] +fn file_uncaught_error_exits_non_zero() { + let unique = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("time should be monotonic") + .as_nanos(); + let script_path = std::env::temp_dir().join(format!("boa-exit-code-{unique}.js")); + fs::write(&script_path, "throw Error('nooo')\n").expect("temp script should be writable"); + + let status = Command::new(boa_bin()) + .arg(&script_path) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .expect("boa should run"); + + let _ = fs::remove_file(&script_path); + + assert!( + !status.success(), + "expected non-zero exit for uncaught file execution error" + ); +}