#![allow(clippy::unwrap_used, clippy::expect_used)]
#![cfg(feature = "localfs")]
mod common;
use common::kernel_at;
use kaish_kernel::ExecuteOptions;
use std::fs;
use tempfile::tempdir;
const BIN: &[u8] = b"\xff\x00\xfe\x80\x01\xc0kaish\xf5";
#[tokio::test]
async fn redirect_stdin_binary_file_feeds_exact_byte_count() {
let dir = tempdir().unwrap();
fs::write(dir.path().join("src.bin"), BIN).unwrap();
let kernel = kernel_at(dir.path());
let result = kernel.execute("wc -c < src.bin").await.unwrap();
assert!(result.ok(), "err={}", result.err);
assert_eq!(
result.text_out().trim(),
BIN.len().to_string(),
"wc -c over a `< file` redirect must see the exact byte count instead \
of erroring on invalid UTF-8 at redirect setup: out={:?}",
result.text_out()
);
}
#[tokio::test]
async fn redirect_stdin_binary_file_cat_round_trips_bytes() {
let dir = tempdir().unwrap();
fs::write(dir.path().join("src.bin"), BIN).unwrap();
let kernel = kernel_at(dir.path());
let result = kernel.execute("cat < src.bin").await.unwrap();
assert!(result.ok(), "err={}", result.err);
assert_eq!(
result.out_bytes(),
Some(BIN),
"cat over a `< file` redirect must round-trip the raw bytes byte-for-byte"
);
}
#[tokio::test]
async fn redirect_stdin_binary_file_text_tool_still_errors_loud() {
let dir = tempdir().unwrap();
fs::write(dir.path().join("src.bin"), BIN).unwrap();
let kernel = kernel_at(dir.path());
let result = kernel.execute("grep x < src.bin").await.unwrap();
assert!(!result.ok(), "grep over binary stdin must fail, not match garbage");
assert!(
result.err.contains("not valid UTF-8"),
"error should name the binary problem, got err={:?}",
result.err
);
}
#[tokio::test]
async fn redirect_stdin_text_file_is_unaffected() {
let dir = tempdir().unwrap();
fs::write(dir.path().join("plain.txt"), "b\na\nc\n").unwrap();
let kernel = kernel_at(dir.path());
let result = kernel.execute("sort < plain.txt").await.unwrap();
assert!(result.ok(), "err={}", result.err);
assert_eq!(result.text_out(), "a\nb\nc\n");
}
#[tokio::test]
async fn redirect_stdin_missing_file_is_still_a_loud_error() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let result = kernel.execute("cat < does-not-exist.txt").await.unwrap();
assert!(!result.ok(), "a missing redirect target must be a loud error");
}
#[tokio::test]
async fn execute_options_with_stdin_bytes_feeds_byte_aware_builtin() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let result = kernel
.execute_with_options("wc -c", ExecuteOptions::new().with_stdin(BIN.to_vec()))
.await
.unwrap();
assert!(result.ok(), "err={}", result.err);
assert_eq!(
result.text_out().trim(),
BIN.len().to_string(),
"ExecuteOptions::with_stdin(Vec<u8>) must feed raw bytes to a byte-aware builtin"
);
}
#[tokio::test]
async fn execute_options_with_stdin_bytes_text_tool_errors_loud() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let result = kernel
.execute_with_options("grep x", ExecuteOptions::new().with_stdin(BIN.to_vec()))
.await
.unwrap();
assert!(!result.ok());
assert!(
result.err.contains("not valid UTF-8"),
"err={:?}",
result.err
);
}
#[tokio::test]
async fn execute_options_with_stdin_text_str_is_unaffected() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let result = kernel
.execute_with_options("cat", ExecuteOptions::new().with_stdin("hello\n"))
.await
.unwrap();
assert!(result.ok(), "err={}", result.err);
assert_eq!(result.text_out(), "hello\n");
}
#[tokio::test]
async fn redirect_stdin_binary_file_xxd_reverse_errors_loud_not_lossy() {
let dir = tempdir().unwrap();
fs::write(dir.path().join("src.bin"), BIN).unwrap();
let kernel = kernel_at(dir.path());
let result = kernel.execute("xxd -r -p < src.bin").await.unwrap();
assert!(!result.ok(), "xxd -r on binary input must fail loud, not lossy-decode it");
assert!(
result.err.contains("not valid UTF-8"),
"error should name the binary problem, got err={:?}",
result.err
);
}
#[tokio::test]
async fn xxd_reverse_file_path_binary_input_errors_loud() {
let dir = tempdir().unwrap();
fs::write(dir.path().join("src.bin"), BIN).unwrap();
let kernel = kernel_at(dir.path());
let result = kernel.execute("xxd -r -p src.bin").await.unwrap();
assert!(!result.ok(), "xxd -r on a binary file must fail loud, not lossy-decode it");
assert!(result.err.contains("not valid UTF-8"), "err={:?}", result.err);
}
#[tokio::test]
async fn xxd_forward_reverse_round_trip_is_unaffected() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let result = kernel.execute("echo -n hello | xxd -p | xxd -r -p").await.unwrap();
assert!(result.ok(), "err={}", result.err);
assert_eq!(result.text_out(), "hello");
}