#![allow(clippy::unwrap_used, clippy::expect_used)]
#![cfg(feature = "localfs")]
use kaish_kernel::{Kernel, KernelConfig};
use rstest::rstest;
async fn out(script: &str) -> String {
let k = Kernel::new(KernelConfig::repl()).expect("kernel");
let r = k
.execute(script)
.await
.unwrap_or_else(|e| panic!("`{script}` must run: {e}"));
r.text_out().trim_end().to_string()
}
#[rstest]
#[case("printf 'a\\tb\\n' > /tmp/kt.tsv; y=$(cut -f2 /tmp/kt.tsv); echo $y", "b")]
#[case("y=$(seq 1 3); echo $y", "1\n2\n3")]
#[case("mkdir -p /tmp/kts && touch /tmp/kts/a.txt; y=$(find /tmp/kts -name '*.txt'); echo $y", "/tmp/kts/a.txt")]
#[case("mkdir -p /tmp/ktg && touch /tmp/ktg/b.txt; y=$(glob '/tmp/ktg/*.txt'); echo $y", "/tmp/ktg/b.txt")]
#[tokio::test]
async fn a_posix_familiar_builtin_binds_text(#[case] script: &str, #[case] expected: &str) {
assert_eq!(out(script).await, expected, "`{script}`");
}
#[tokio::test]
async fn cut_and_awk_agree_now() {
let setup = "printf 'a\\tb\\n' > /tmp/kt2.tsv; ";
let cut = out(&format!("{setup}y=$(cut -f2 /tmp/kt2.tsv); echo $y")).await;
let awk = out(&format!("{setup}y=$(awk '{{print $2}}' /tmp/kt2.tsv); echo $y")).await;
assert_eq!(cut, awk, "cut and awk do the same job here");
assert_eq!(cut, "b");
}
#[rstest]
#[case("xs=$(fromjson '[10,20]'); echo ${xs[0]}", "10")]
#[case("r=$(fromjson '{\"a\":1}'); echo ${r[a]}", "1")]
#[case("r=$(jq -c . <<< '{\"a\":7}'); echo ${r[a]}", "7")]
#[case("ks=$(keys $(fromjson '{\"a\":1}')); echo ${ks[0]}", "a")]
#[case("vs=$(values $(fromjson '{\"a\":9}')); echo ${vs[0]}", "9")]
#[tokio::test]
async fn a_value_builtin_stays_typed(#[case] script: &str, #[case] expected: &str) {
assert_eq!(out(script).await, expected, "`{script}`");
}
#[rstest]
#[case("seq 1 3 | jq -c .", "[1,2,3]")]
#[case("printf 'a\\tb\\n' > /tmp/kt3.tsv; cut -f2 /tmp/kt3.tsv | jq -c .", "[\"b\"]")]
#[tokio::test]
async fn the_pipeline_sideband_is_untouched(#[case] script: &str, #[case] expected: &str) {
assert_eq!(out(script).await, expected, "`{script}`");
}
#[rstest]
#[case("seq 1 3 --json", "[\"1\",\"2\",\"3\"]")]
#[case("printf 'a\\tb\\n' > /tmp/kt4.tsv; cut -f2 /tmp/kt4.tsv --json", "[\"b\"]")]
#[tokio::test]
async fn json_output_is_unchanged(#[case] script: &str, #[case] expected: &str) {
assert_eq!(out(script).await, expected, "`{script}`");
}
#[rstest]
#[case("for i in $(seq 1 3); do echo \"i=$i\"; done", "i=1\ni=2\ni=3")]
#[case("printf 'a\\tb\\nc\\td\\n' > /tmp/kt5.tsv; for v in $(cut -f2 /tmp/kt5.tsv); do echo \"v=$v\"; done", "v=b\nv=d")]
#[tokio::test]
async fn iteration_is_unchanged(#[case] script: &str, #[case] expected: &str) {
assert_eq!(out(script).await, expected, "`{script}`");
}
#[rstest]
#[case("x=$(if true; then fromjson '[1,2]'; fi); echo ${x[0]}", "1")]
#[case("x=$(for i in 1; do fromjson '[9,8]'; done); echo ${x[0]}", "9")]
#[case("x=$(while true; do fromjson '[5]'; break; done); echo ${x[0]}", "5")]
#[case("x=$(case a in a) fromjson '[3]';; esac); echo ${x[0]}", "3")]
#[case("x=$(true && fromjson '[1,2]'); echo ${x[0]}", "1")]
#[case("x=$(false || fromjson '[1,2]'); echo ${x[0]}", "1")]
#[tokio::test]
async fn a_typed_value_survives_a_compound_statement(
#[case] script: &str,
#[case] expected: &str,
) {
assert_eq!(out(script).await, expected, "`{script}`");
}
#[tokio::test]
async fn a_chain_does_not_type_the_right_side_from_the_left() {
let script = "printf 'a\tb\n' > /tmp/ktinv.tsv; x=$(fromjson '[1,2]' && cut -f2 /tmp/ktinv.tsv); echo $x";
assert_eq!(out(script).await, "[1,2]b", "both texts, neither typed");
}
#[tokio::test]
async fn a_valueless_signal_does_not_erase_the_bodys_value() {
assert_eq!(
out("x=$(for i in 1 2; do fromjson '[7]'; continue; done); echo ${x[0]}").await,
"7"
);
assert_eq!(out("x=$(while true; do echo hi; break; done); echo $x").await, "hi");
}
#[tokio::test]
async fn a_redispatching_wrapper_keeps_the_inner_declaration() {
let k = Kernel::new(KernelConfig::repl()).expect("kernel").into_arc();
let r = k
.execute("x=$(timeout 5 fromjson '[1,2]'); echo ${x[0]}")
.await
.expect("execute");
assert_eq!(r.text_out().trim_end(), "1", "err={:?}", r.err);
}
#[rstest]
#[case("x=$(fromjsonl '{\"a\":1}'); echo ${x[0]}", "{\"a\":1}")]
#[case("x=$(split 'a b c'); echo ${x[1]}", "b")]
#[case("x=$(typeof 5); echo $x", "number")]
#[tokio::test]
async fn the_rest_of_the_typed_set(#[case] script: &str, #[case] expected: &str) {
assert_eq!(out(script).await, expected, "`{script}`");
}