#![cfg(feature = "localfs")]
#![allow(clippy::unwrap_used, clippy::expect_used)]
use kaish_kernel::{Kernel, KernelConfig};
#[tokio::test]
async fn malformed_cmdsubst_in_quotes_is_loud() {
let kernel = Kernel::new(KernelConfig::repl()).expect("kernel");
let res = kernel.execute("echo \"$(if true; echo 1; fi)\"").await;
assert!(
res.is_err(),
"malformed quoted $() must be a loud parse error, got: {res:?}"
);
}
#[tokio::test]
async fn malformed_cmdsubst_unquoted_still_loud() {
let kernel = Kernel::new(KernelConfig::repl()).expect("kernel");
assert!(kernel
.execute("echo $(if true; echo 1; fi)")
.await
.is_err());
}
#[tokio::test]
async fn valid_cmdsubst_in_quotes_runs() {
let kernel = Kernel::new(KernelConfig::repl()).expect("kernel");
let r = kernel.execute("echo \"$(echo ok)\"").await.expect("execute");
assert_eq!(r.code, 0);
assert_eq!(r.text_out().trim(), "ok");
}
#[tokio::test]
async fn plain_text_with_cmdsubst_interpolation_runs() {
let kernel = Kernel::new(KernelConfig::repl()).expect("kernel");
let r = kernel
.execute("echo \"pre $(echo mid) post\"")
.await
.expect("execute");
assert_eq!(r.code, 0);
assert_eq!(r.text_out().trim(), "pre mid post");
}
#[tokio::test]
async fn unterminated_cmdsubst_in_quotes_is_loud() {
let kernel = Kernel::new(KernelConfig::repl()).expect("kernel");
let res = kernel.execute("echo \"pre $(echo hi\"").await;
let err = res
.expect_err("unterminated quoted $( must be a loud parse error")
.to_string();
assert!(
err.contains("unterminated command substitution") && err.contains(')'),
"expected an unterminated-command-substitution message naming the missing `)`, got: {err}"
);
}
#[tokio::test]
async fn unterminated_cmdsubst_unquoted_matches_message() {
let kernel = Kernel::new(KernelConfig::repl()).expect("kernel");
let err = kernel
.execute("echo $(echo hi")
.await
.expect_err("unterminated unquoted $( must be a loud parse error")
.to_string();
assert!(
err.contains("unterminated command substitution") && err.contains(')'),
"expected an unterminated-command-substitution message naming the missing `)`, got: {err}"
);
}
#[tokio::test]
async fn terminated_cmdsubst_in_quotes_still_runs() {
let kernel = Kernel::new(KernelConfig::repl()).expect("kernel");
let r = kernel
.execute("echo \"pre $(echo hi)\"")
.await
.expect("execute");
assert_eq!(r.code, 0);
assert_eq!(r.text_out().trim(), "pre hi");
}
#[tokio::test]
async fn unterminated_and_unparseable_cmdsubst_in_quotes_is_loud() {
let kernel = Kernel::new(KernelConfig::repl()).expect("kernel");
let res = kernel.execute("echo \"pre $(;;\"").await;
assert!(
res.is_err(),
"unterminated + unparseable quoted $( must be a loud parse error, got: {res:?}"
);
}
#[tokio::test]
async fn second_unterminated_cmdsubst_in_quotes_is_loud() {
let kernel = Kernel::new(KernelConfig::repl()).expect("kernel");
let res = kernel.execute("echo \"a $(echo b) c $(echo d\"").await;
assert!(
res.is_err(),
"a later unterminated quoted $( must still be a loud parse error, got: {res:?}"
);
}