use fsys::builder;
use std::path::PathBuf;
use std::sync::atomic::{AtomicU64, Ordering};
static C: AtomicU64 = AtomicU64::new(0);
fn tmp_path(tag: &str) -> PathBuf {
let n = C.fetch_add(1, Ordering::Relaxed);
std::env::temp_dir().join(format!("fsys_edge_{}_{}_{}", std::process::id(), n, tag))
}
fn tmp_dir(tag: &str) -> PathBuf {
let p = tmp_path(tag);
std::fs::create_dir_all(&p).unwrap();
p
}
struct CleanupFile(PathBuf);
impl Drop for CleanupFile {
fn drop(&mut self) {
let _ = std::fs::remove_file(&self.0);
}
}
struct CleanupDir(PathBuf);
impl Drop for CleanupDir {
fn drop(&mut self) {
let _ = std::fs::remove_dir_all(&self.0);
}
}
#[test]
fn zero_byte_write_then_read_round_trips() {
let path = tmp_path("zero_byte");
let _g = CleanupFile(path.clone());
let fs = builder().build().expect("handle");
fs.write(&path, b"").expect("write zero bytes");
let read = fs.read(&path).expect("read zero bytes");
assert!(read.is_empty());
assert_eq!(fs.size(&path).expect("size"), 0);
}
#[test]
fn page_size_payload_round_trips() {
let page = fsys::os::info().page_size.max(4096);
let path = tmp_path("page_size");
let _g = CleanupFile(path.clone());
let fs = builder().build().expect("handle");
let payload = vec![0xA5u8; page];
fs.write(&path, &payload).expect("write");
let read = fs.read(&path).expect("read");
assert_eq!(read, payload);
}
#[test]
fn single_sector_payload_round_trips() {
let path = tmp_path("one_sector");
let _g = CleanupFile(path.clone());
let fs = builder().build().expect("handle");
let payload = vec![0x5Au8; 512];
fs.write(&path, &payload).expect("write");
let read = fs.read(&path).expect("read");
assert_eq!(read, payload);
}
#[test]
fn one_byte_payload_round_trips() {
let path = tmp_path("one_byte");
let _g = CleanupFile(path.clone());
let fs = builder().build().expect("handle");
fs.write(&path, b"X").expect("write");
let read = fs.read(&path).expect("read");
assert_eq!(read, b"X");
}
#[test]
fn unicode_and_emoji_paths_round_trip() {
let dir = tmp_dir("unicode");
let _g = CleanupDir(dir.clone());
let fs = builder().build().expect("handle");
let cases = [
"héllo.txt",
"日本語ファイル.txt",
"café résumé.txt",
"smile_😀.txt",
"rocket_🚀.txt",
];
for name in cases {
let path = dir.join(name);
fs.write(&path, name.as_bytes()).expect("write unicode");
let read = fs.read(&path).expect("read unicode");
assert_eq!(read, name.as_bytes());
}
}
#[test]
fn deeply_nested_directory_tree_walks_clean() {
let root = tmp_dir("deep");
let _g = CleanupDir(root.clone());
let fs = builder().build().expect("handle");
let mut p = root.clone();
for i in 0..20 {
p = p.join(format!("d{i:02}"));
}
fs.mkdir_all(&p).expect("mkdir deep");
fs.write(p.join("leaf.txt"), b"reached")
.expect("write leaf");
let scan = fs.scan_all(&root).expect("scan_all deep");
assert!(scan.len() >= 21, "expected ≥21 entries, got {}", scan.len());
let count = fs.count_all(&root).expect("count_all deep");
assert_eq!(count, 1, "exactly one regular file in tree");
}
#[test]
fn long_filename_within_limits() {
let dir = tmp_dir("longname");
let _g = CleanupDir(dir.clone());
let fs = builder().build().expect("handle");
let name: String = "a".repeat(100);
let path = dir.join(format!("{name}.txt"));
fs.write(&path, b"x").expect("write long-name");
assert!(fs.exists(&path).expect("exists"));
}
#[test]
fn write_then_rename_then_write_again_atomic() {
let dir = tmp_dir("rename_race");
let _g = CleanupDir(dir.clone());
let fs = builder().build().expect("handle");
let a = dir.join("a.dat");
let b = dir.join("b.dat");
fs.write(&a, b"first").expect("write a");
fs.rename(&a, &b).expect("rename a→b");
assert!(!fs.exists(&a).expect("a gone"));
assert!(fs.exists(&b).expect("b present"));
fs.write(&a, b"second").expect("write a (post-rename)");
let ra = fs.read(&a).expect("read a");
let rb = fs.read(&b).expect("read b");
assert_eq!(ra, b"second");
assert_eq!(rb, b"first");
}
#[test]
fn write_copy_zero_byte_then_replace_round_trip() {
let path = tmp_path("wcopy_zero");
let _g = CleanupFile(path.clone());
let fs = builder().build().expect("handle");
fs.write(&path, b"").expect("create empty");
fs.write_copy(&path, b"non-empty replacement")
.expect("write_copy");
assert_eq!(fs.read(&path).expect("read"), b"non-empty replacement");
}
#[test]
fn truncate_to_zero_then_extend() {
let path = tmp_path("trunc_zero");
let _g = CleanupFile(path.clone());
let fs = builder().build().expect("handle");
fs.write(&path, b"abcdefgh").expect("write");
fs.truncate(&path, 0).expect("truncate to 0");
assert_eq!(fs.size(&path).expect("size"), 0);
fs.write(&path, b"new").expect("write again");
assert_eq!(fs.read(&path).expect("read"), b"new");
}
#[test]
fn append_to_nonexistent_creates_file() {
let path = tmp_path("append_create");
let _g = CleanupFile(path.clone());
let fs = builder().build().expect("handle");
fs.append(&path, b"hello").expect("append (creates)");
assert_eq!(fs.read(&path).expect("read"), b"hello");
}