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
CI / update-e2e (windows x64) (push) Waiting to run
GPU evidence / GPU 判据自测(不需 GPU;跳过 ≠ 已验证) (push) Waiting to run
GPU evidence / GPU 证据 — 探测可用产物与硬件适配器 (push) Waiting to run
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
Release guard / 发布标记语义守门(push tag → 稳定版) (push) Waiting to run
Signing status(播报,不是门禁) / 判据自测(三行/退出码/变异重放/接线) (push) Waiting to run
Signing status(播报,不是门禁) / 签名就绪度(播报) (push) Waiting to run
Release / 选槽位(默认四个:Windows 两档 + Linux 两档) (push) Waiting to run
本批内容见 CHANGELOG.md 的 0.2.4 段。按 D41 用孤儿快照推 main,保留「公开史只有里程碑」的模型。
50 lines
1.6 KiB
Rust
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, "并发写要能拿到不同的临时名");
|
|
}
|