#![allow(clippy::unwrap_used, clippy::expect_used)]
#![cfg(feature = "localfs")]
mod common;
use common::kernel_at;
use kaish_kernel::{pipe_stream_default, ExecuteOptions};
use std::fs;
use tempfile::tempdir;
const ORIGINAL: &[u8] = b"[IMPORTANT DATA]\n";
fn exhausted_pipe() -> kaish_kernel::PipeReader {
let (writer, reader) = pipe_stream_default();
drop(writer);
reader
}
#[tokio::test]
async fn write_with_exhausted_session_stdin_refuses_and_leaves_the_file_intact() {
let dir = tempdir().unwrap();
let target = dir.path().join("notes.md");
fs::write(&target, ORIGINAL).unwrap();
let kernel = kernel_at(dir.path());
let result = kernel
.execute_with_pipe_stdin("write notes.md", ExecuteOptions::new(), exhausted_pipe())
.await
.unwrap();
assert_eq!(
fs::read(&target).unwrap(),
ORIGINAL,
"the file must be byte-identical — an error that still truncates is the same bug"
);
assert_eq!(result.code, 1, "expected a refusal, got: {}", result.err);
}
#[tokio::test]
async fn write_with_no_stdin_at_all_refuses_and_leaves_the_file_intact() {
let dir = tempdir().unwrap();
let target = dir.path().join("notes.md");
fs::write(&target, ORIGINAL).unwrap();
let kernel = kernel_at(dir.path());
let result = kernel.execute("write notes.md").await.unwrap();
assert_eq!(fs::read(&target).unwrap(), ORIGINAL, "file must be untouched");
assert_eq!(result.code, 1, "expected a refusal, got: {}", result.err);
}
#[tokio::test]
async fn the_refusal_says_the_file_is_unchanged() {
let dir = tempdir().unwrap();
fs::write(dir.path().join("notes.md"), ORIGINAL).unwrap();
let kernel = kernel_at(dir.path());
let result = kernel.execute("write notes.md").await.unwrap();
assert!(
result.err.contains("notes.md") && result.err.contains("unchanged"),
"refusal should name the file and say it is unchanged, got: {}",
result.err
);
}
#[tokio::test]
async fn an_empty_upstream_stage_truncates() {
let dir = tempdir().unwrap();
let target = dir.path().join("notes.md");
fs::write(&target, ORIGINAL).unwrap();
let kernel = kernel_at(dir.path());
let result = kernel.execute("printf '' | write notes.md").await.unwrap();
assert_eq!(result.code, 0, "expected a truncate, got: {}", result.err);
assert!(
fs::read(&target).unwrap().is_empty(),
"an explicitly empty pipe must truncate to zero bytes"
);
}
#[tokio::test]
async fn a_redirect_from_an_empty_file_truncates() {
let dir = tempdir().unwrap();
let target = dir.path().join("notes.md");
fs::write(&target, ORIGINAL).unwrap();
fs::write(dir.path().join("empty"), b"").unwrap();
let kernel = kernel_at(dir.path());
let result = kernel.execute("write notes.md < empty").await.unwrap();
assert_eq!(result.code, 0, "expected a truncate, got: {}", result.err);
assert!(fs::read(&target).unwrap().is_empty(), "redirect must truncate");
}
#[tokio::test]
async fn a_content_operand_still_writes() {
let dir = tempdir().unwrap();
let target = dir.path().join("notes.md");
fs::write(&target, ORIGINAL).unwrap();
let kernel = kernel_at(dir.path());
let result = kernel.execute("write notes.md 'new content'").await.unwrap();
assert_eq!(result.code, 0, "err={}", result.err);
assert_eq!(fs::read(&target).unwrap(), b"new content");
}
#[tokio::test]
async fn a_content_operand_wins_over_exhausted_session_stdin() {
let dir = tempdir().unwrap();
let target = dir.path().join("notes.md");
fs::write(&target, ORIGINAL).unwrap();
let kernel = kernel_at(dir.path());
let result = kernel
.execute_with_pipe_stdin(
"write notes.md 'from operand'",
ExecuteOptions::new(),
exhausted_pipe(),
)
.await
.unwrap();
assert_eq!(result.code, 0, "err={}", result.err);
assert_eq!(fs::read(&target).unwrap(), b"from operand");
}
#[tokio::test]
async fn piped_content_still_writes() {
let dir = tempdir().unwrap();
let target = dir.path().join("notes.md");
fs::write(&target, ORIGINAL).unwrap();
let kernel = kernel_at(dir.path());
let result = kernel.execute("echo x | write notes.md").await.unwrap();
assert_eq!(result.code, 0, "err={}", result.err);
assert_eq!(fs::read(&target).unwrap(), b"x\n");
}
#[tokio::test]
async fn session_stdin_carrying_real_bytes_still_writes() {
let dir = tempdir().unwrap();
let target = dir.path().join("notes.md");
fs::write(&target, ORIGINAL).unwrap();
let kernel = kernel_at(dir.path());
let (writer, reader) = pipe_stream_default();
writer.write_bytes(b"from the session pipe").await.unwrap();
drop(writer);
let result = kernel
.execute_with_pipe_stdin("write notes.md", ExecuteOptions::new(), reader)
.await
.unwrap();
assert_eq!(result.code, 0, "err={}", result.err);
assert_eq!(fs::read(&target).unwrap(), b"from the session pipe");
}