use bashkit::Bash;
#[tokio::test]
async fn urandom_no_replacement_chars() {
let mut bash = Bash::new();
let result = bash
.exec("head -c 100 /dev/urandom | od -A n -t x1 | tr -d ' \\n'")
.await
.unwrap();
let hex = result.stdout.trim();
assert!(
!hex.contains("efbfbd"),
"Output should not contain UTF-8 replacement chars: {}",
&hex[..hex.len().min(60)]
);
}
#[tokio::test]
async fn urandom_head_char_count() {
let mut bash = Bash::new();
for n in [1, 4, 8, 16, 32] {
let result = bash
.exec(&format!("head -c {n} /dev/urandom | wc -m"))
.await
.unwrap();
let count: usize = result.stdout.trim().parse().unwrap_or(0);
assert_eq!(
count, n,
"head -c {n} /dev/urandom | wc -m should produce exactly {n} chars"
);
}
}
#[tokio::test]
async fn urandom_tr_filter_alphanumeric() {
let mut bash = Bash::new();
let result = bash
.exec("LC_ALL=C tr -dc 'a-z0-9' < /dev/urandom | head -c 8")
.await
.unwrap();
let output = result.stdout.trim();
assert_eq!(
output.len(),
8,
"Should produce exactly 8 chars, got {}: {:?}",
output.len(),
output
);
assert!(
output
.chars()
.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit()),
"All chars should be a-z0-9, got: {:?}",
output
);
}
#[tokio::test]
async fn utf8_file_reads_do_not_mojibake() {
use std::path::Path;
let mut bash = Bash::new();
let fs = bash.fs();
fs.write_file(Path::new("/tmp/utf8.txt"), "café\n".as_bytes())
.await
.unwrap();
let result = bash.exec("cat < /tmp/utf8.txt").await.unwrap();
assert_eq!(result.exit_code, 0);
assert_eq!(result.stdout, "café\n");
let result = bash.exec("head -n 1 /tmp/utf8.txt").await.unwrap();
assert_eq!(result.exit_code, 0);
assert_eq!(result.stdout, "café\n");
}
#[tokio::test]
async fn utf8_script_file_decodes_as_utf8() {
use std::path::Path;
let mut bash = Bash::new();
let fs = bash.fs();
fs.write_file(Path::new("/tmp/script.sh"), "echo café\n".as_bytes())
.await
.unwrap();
let result = bash.exec("bash /tmp/script.sh").await.unwrap();
assert_eq!(result.exit_code, 0);
assert_eq!(result.stdout, "café\n");
}