use kaish_kernel::Kernel;
#[tokio::test]
async fn break_keeps_the_output_produced_before_it() {
let kernel = Kernel::transient().unwrap();
let result = kernel
.execute("for f in a b c; do echo $f; break; done")
.await
.unwrap();
assert!(result.ok(), "script should succeed: err={}", result.err);
assert_eq!(result.text_out().trim(), "a");
}
#[tokio::test]
async fn continue_keeps_the_output_of_every_iteration() {
let kernel = Kernel::transient().unwrap();
let result = kernel
.execute("for f in a b c; do echo $f; continue; done")
.await
.unwrap();
assert!(result.ok(), "script should succeed: err={}", result.err);
assert_eq!(result.text_out().trim(), "a\nb\nc");
}
#[tokio::test]
async fn break_2_carries_both_loops_output_out_exactly_once() {
let kernel = Kernel::transient().unwrap();
let result = kernel
.execute("for o in x; do echo outer=$o; for i in p q; do echo inner=$i; break 2; done; done")
.await
.unwrap();
assert!(result.ok(), "script should succeed: err={}", result.err);
assert_eq!(result.text_out().trim(), "outer=x\ninner=p");
}
#[tokio::test]
async fn continue_2_carries_the_inner_output_out_exactly_once() {
let kernel = Kernel::transient().unwrap();
let result = kernel
.execute("for o in x y; do echo outer=$o; for i in p; do echo inner=$i; continue 2; done; done")
.await
.unwrap();
assert!(result.ok(), "script should succeed: err={}", result.err);
assert_eq!(
result.text_out().trim(),
"outer=x\ninner=p\nouter=y\ninner=p"
);
}
#[tokio::test]
async fn exit_from_a_for_loop_keeps_the_output_already_produced() {
let kernel = Kernel::transient().unwrap();
let result = kernel
.execute("for f in a b; do echo $f; exit 3; done")
.await
.unwrap();
assert_eq!(result.code, 3, "exit code should be the one `exit` named");
assert_eq!(
result.text_out().trim(),
"a",
"the iteration that ran before `exit` printed 'a'; it must not be discarded"
);
}
#[tokio::test]
async fn exit_from_a_while_loop_keeps_the_output_already_produced() {
let kernel = Kernel::transient().unwrap();
let result = kernel
.execute("while true; do echo hi; exit 3; done")
.await
.unwrap();
assert_eq!(result.code, 3);
assert_eq!(result.text_out().trim(), "hi");
}
#[tokio::test]
async fn exit_keeps_both_earlier_statements_and_the_loop_output() {
let kernel = Kernel::transient().unwrap();
let result = kernel
.execute("echo pre; for f in a b; do echo $f; exit 3; done")
.await
.unwrap();
assert_eq!(result.code, 3);
assert_eq!(result.text_out().trim(), "pre\na");
}
#[tokio::test]
async fn exit_from_a_nested_loop_emits_each_level_exactly_once() {
let kernel = Kernel::transient().unwrap();
let result = kernel
.execute("for o in x; do echo outer=$o; for i in p q; do echo inner=$i; exit 4; done; done")
.await
.unwrap();
assert_eq!(result.code, 4);
assert_eq!(result.text_out().trim(), "outer=x\ninner=p");
}
#[tokio::test]
async fn exit_from_an_if_branch_keeps_the_branch_output() {
let kernel = Kernel::transient().unwrap();
let result = kernel
.execute("if true; then echo x; exit 1; fi")
.await
.unwrap();
assert_eq!(result.code, 1);
assert_eq!(result.text_out().trim(), "x");
}
#[tokio::test]
async fn exit_from_a_case_branch_keeps_the_branch_output() {
let kernel = Kernel::transient().unwrap();
let result = kernel
.execute("case a in a) echo hit; exit 1;; esac")
.await
.unwrap();
assert_eq!(result.code, 1);
assert_eq!(result.text_out().trim(), "hit");
}
#[tokio::test]
async fn exit_from_the_right_of_an_and_chain_keeps_the_left_output() {
let kernel = Kernel::transient().unwrap();
let result = kernel.execute("echo pre && exit 1").await.unwrap();
assert_eq!(result.code, 1);
assert_eq!(result.text_out().trim(), "pre");
}
#[tokio::test]
async fn exit_from_an_if_inside_a_loop_keeps_both() {
let kernel = Kernel::transient().unwrap();
let result = kernel
.execute("for f in a; do echo loop=$f; if true; then echo branch; exit 1; fi; done")
.await
.unwrap();
assert_eq!(result.code, 1);
assert_eq!(result.text_out().trim(), "loop=a\nbranch");
}
#[tokio::test]
async fn exit_from_a_loop_in_a_function_keeps_the_output() {
let kernel = Kernel::transient().unwrap();
let result = kernel
.execute("f() { for x in a b; do echo $x; exit 3; done; }; f")
.await
.unwrap();
assert_eq!(result.code, 3);
assert_eq!(result.text_out().trim(), "a");
}
#[tokio::test]
async fn return_from_a_nested_loop_in_a_function_keeps_both_levels() {
let kernel = Kernel::transient().unwrap();
let result = kernel
.execute("f() { for o in x; do echo outer=$o; for i in p q; do echo inner=$i; return 5; done; done; }; f")
.await
.unwrap();
assert_eq!(result.code, 5);
assert_eq!(result.text_out().trim(), "outer=x\ninner=p");
}
#[tokio::test]
async fn return_from_a_loop_in_a_function_keeps_the_output() {
let kernel = Kernel::transient().unwrap();
let result = kernel
.execute("f() { for x in a b; do echo $x; return 5; done; }; f")
.await
.unwrap();
assert_eq!(result.code, 5);
assert_eq!(
result.text_out().trim(),
"a",
"the iteration that ran before `return` printed 'a'; it must not be discarded"
);
}