Files
Unlucky-Launcher/crates/core/tests/setting/atomic_write.rs
T
AskaEth 8a8e5ca0c0
CI / fmt (rustfmt --check) (push) Waiting to run
CI / clippy (ubuntu-latest) (push) Waiting to run
CI / clippy (windows-latest) (push) Waiting to run
CI / test (ubuntu-latest) (push) Waiting to run
CI / test (windows-latest) (push) Waiting to run
CI / build release (ubuntu-latest) (push) Waiting to run
CI / build release (windows-latest) (push) Waiting to run
CI / runtime smoke (ubuntu x64, xvfb) (push) Waiting to run
CI / runtime smoke (macos arm64, probe) (push) Skipped
Guards / core 零 UI 守门 (push) Waiting to run
Guards / presenter 零 UI 守门 (push) Waiting to run
Guards / design 零第三方依赖守门 (push) Waiting to run
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Waiting to run
Guards / 文件行数 ≤400 守门 (push) Waiting to run
Guards / 依赖许可与来源(cargo-deny) (push) Waiting to run
Unlucky Launcher v0.2.0
首个 iced + Material 3 Expressive 版本的源码快照。
完整历史与日常提交在 dev 分支;main 只放阶段性快照。
2026-11-05 14:22:11 +08:00

50 lines
1.6 KiB
Rust

//! 原子写:覆盖语义、父目录创建、不留临时文件、可选读。
use unlucky_core::platform::atomic::{read_optional, tmp_path, write_atomic};
use crate::common::{dir_entries, TempDir};
#[test]
fn writes_and_replaces_in_place() {
let temp = TempDir::new("atomic");
let path = temp.child("config/launcher.json");
write_atomic(&path, b"{\"a\":1}").expect("首次写");
assert_eq!(temp.read("config/launcher.json"), "{\"a\":1}");
write_atomic(&path, b"{\"a\":2}").expect("覆盖写");
assert_eq!(temp.read("config/launcher.json"), "{\"a\":2}");
// 目录里只该有目标文件,临时文件必须被改名掉。
assert_eq!(dir_entries(&temp.child("config")), vec!["launcher.json"]);
}
#[test]
fn read_optional_distinguishes_missing_from_failure() {
let temp = TempDir::new("atomic-read");
let path = temp.child("nope.json");
assert!(read_optional(&path).expect("读缺失文件").is_none());
temp.write("here.json", "内容");
let bytes = read_optional(&temp.child("here.json"))
.expect("读文件")
.expect("有内容");
assert_eq!(bytes, "内容".as_bytes());
}
#[test]
fn tmp_name_stays_in_same_directory() {
let temp = TempDir::new("atomic-tmp");
let path = temp.child("config/profiles.json");
let tmp = tmp_path(&path);
assert_eq!(
tmp.parent(),
path.parent(),
"临时文件必须同目录(rename 才原子)"
);
assert_ne!(tmp, path);
let first = tmp_path(&path);
let second = tmp_path(&path);
assert_ne!(first, second, "并发写要能拿到不同的临时名");
}