#![allow(clippy::unwrap_used, clippy::expect_used)]
#![cfg(feature = "localfs")]
mod common;
use common::{kernel_at, run};
use std::fs;
use tempfile::tempdir;
#[tokio::test]
async fn dd_skip_without_count_skips_bytes() {
let dir = tempdir().unwrap();
let test_file = dir.path().join("input.bin");
fs::write(&test_file, b"\x00\x01\x02\x03\x04\x05\x06\x07").unwrap();
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "dd if=input.bin skip=2 bs=1 | xxd -p").await;
assert_eq!(code, 0, "dd skip=2 bs=1 should succeed, got: {out:?}");
assert_eq!(
out, "020304050607",
"dd skip=2 bs=1 should skip first 2 bytes; got: {out:?}"
);
}
#[tokio::test]
async fn dd_skip_without_count_respects_block_size() {
let dir = tempdir().unwrap();
let test_file = dir.path().join("input.bin");
fs::write(&test_file, b"\x00\x01\x02\x03\x04\x05\x06\x07").unwrap();
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "dd if=input.bin skip=2 bs=2 | xxd -p").await;
assert_eq!(code, 0, "dd skip=2 bs=2 should succeed: {out:?}");
assert_eq!(
out, "04050607",
"dd skip=2 bs=2 should skip first 4 bytes; got: {out:?}"
);
}
#[tokio::test]
async fn dd_no_skip_no_count_reads_all() {
let dir = tempdir().unwrap();
let test_file = dir.path().join("input.bin");
fs::write(&test_file, b"\x00\x01\x02\x03").unwrap();
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "dd if=input.bin bs=1 | xxd -p").await;
assert_eq!(code, 0);
assert_eq!(out, "00010203", "dd without skip/count must read all; got: {out:?}");
}
#[tokio::test]
async fn dd_skip_zero_reads_all() {
let dir = tempdir().unwrap();
let test_file = dir.path().join("input.bin");
fs::write(&test_file, b"\x00\x01\x02\x03").unwrap();
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "dd if=input.bin skip=0 bs=1 | xxd -p").await;
assert_eq!(code, 0);
assert_eq!(out, "00010203", "dd skip=0 must read all bytes; got: {out:?}");
}
#[tokio::test]
async fn dd_skip_with_count_still_works() {
let dir = tempdir().unwrap();
let test_file = dir.path().join("input.bin");
fs::write(&test_file, b"\x00\x01\x02\x03\x04\x05\x06\x07").unwrap();
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "dd if=input.bin skip=2 bs=1 count=3 | xxd -p").await;
assert_eq!(code, 0, "dd skip=2 count=3 should succeed: {out:?}");
assert_eq!(
out, "020304",
"dd skip=2 bs=1 count=3 should yield 3 bytes starting at offset 2; got: {out:?}"
);
}
#[tokio::test]
async fn xxd_reverse_plain_even_nibbles_roundtrip() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "echo 68656c6c6f | xxd -r -p").await;
assert_eq!(code, 0);
assert_eq!(out, "hello", "xxd -r -p of even hex should round-trip; got: {out:?}");
}
#[tokio::test]
async fn xxd_reverse_plain_odd_nibble_dropped_silently() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let result = kernel
.execute("echo 68656c6c6f1 | xxd -r -p")
.await
.unwrap();
assert_eq!(result.code, 0, "xxd -r -p with trailing odd nibble must exit 0");
assert_eq!(
result.text_out().as_ref(),
"hello",
"xxd -r -p must drop trailing odd nibble silently (matches GNU xxd); got: {:?}",
result.text_out()
);
}
#[tokio::test]
async fn xxd_reverse_plain_single_nibble_produces_empty() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let result = kernel
.execute("echo c | xxd -r -p | xxd -p")
.await
.unwrap();
assert_eq!(result.code, 0, "xxd with single nibble must exit 0");
assert_eq!(
result.text_out().trim(),
"",
"single nibble should yield empty output; got: {:?}",
result.text_out()
);
}
#[tokio::test]
async fn xxd_reverse_plain_strips_whitespace() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "echo 'ab cd ef' | xxd -r -p | xxd -p").await;
assert_eq!(code, 0);
assert_eq!(out, "abcdef", "xxd -r -p must strip whitespace; got: {out:?}");
}
#[tokio::test]
async fn seq_w_negative_numbers_padded() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "seq -w -3 3").await;
assert_eq!(code, 0, "seq -w -3 3 should succeed: {out:?}");
let lines: Vec<&str> = out.lines().collect();
assert_eq!(
lines,
vec!["-3", "-2", "-1", "00", "01", "02", "03"],
"seq -w -3 3 must pad positives to width of widest item (including sign); got: {lines:?}"
);
}
#[tokio::test]
async fn seq_w_negative_numbers_wider_padding() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "seq -w -10 2").await;
assert_eq!(code, 0, "seq -w -10 2 should succeed: {out:?}");
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines[0], "-10", "first line should be -10; got: {:?}", lines[0]);
assert_eq!(lines[1], "-09", "second line should be -09; got: {:?}", lines[1]);
assert_eq!(
lines[10], "000",
"first non-negative should be 000 (width 3); got: {:?}",
lines[10]
);
assert_eq!(lines[12], "002", "last line should be 002; got: {:?}", lines[12]);
}
#[tokio::test]
async fn seq_w_positive_only_unaffected() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "seq -w 1 10").await;
assert_eq!(code, 0);
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines[0], "01", "first should be 01; got: {:?}", lines[0]);
assert_eq!(lines[9], "10", "last should be 10; got: {:?}", lines[9]);
}
#[tokio::test]
async fn seq_w_negatives_same_width_as_padded_positives() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "seq -w -2 2").await;
assert_eq!(code, 0, "seq -w -2 2 should succeed: {out:?}");
let lines: Vec<&str> = out.lines().collect();
assert_eq!(
lines,
vec!["-2", "-1", "00", "01", "02"],
"seq -w -2 2 must pad positives to match negative width; got: {lines:?}"
);
}