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
86 lines
3.6 KiB
Rust
86 lines
3.6 KiB
Rust
//! 导出的用例:真的落盘、真的报字节数、真的在有截断时说一句。
|
||
//!
|
||
//! 从 `tests.rs` 拆出(那个文件贴着 400 行硬线)。共用父模块的 `report()` 夹具。
|
||
|
||
use unlucky_i18n::Lang;
|
||
|
||
use super::report;
|
||
use crate::app::dialog::export;
|
||
|
||
/// 导出:真的落盘、真的报出路径与字节数(**没有 crash-report 也要能导出**)。
|
||
#[test]
|
||
fn export_writes_a_bundle_even_without_a_crash_report() {
|
||
let root = std::env::temp_dir().join(format!("ull-m187-export-{}", std::process::id()));
|
||
let _ = std::fs::remove_dir_all(&root);
|
||
std::fs::create_dir_all(root.join("logs")).expect("建目录");
|
||
std::fs::write(root.join("logs").join("launcher.log"), "[launch] boom\n").expect("写日志");
|
||
|
||
let mut spec_report = report(false, vec!["Error: boom".to_string()]);
|
||
spec_report.launcher_logs = Some(root.join("logs"));
|
||
spec_report.session_log = None;
|
||
spec_report.run_dir = None;
|
||
spec_report.version_json = None;
|
||
|
||
let done = export::export(&spec_report, Lang::ZhCn);
|
||
let text = done.text.clone();
|
||
assert!(done.ok, "{text}");
|
||
assert_eq!(done.truncated, 0);
|
||
assert!(text.contains("已导出"), "{text}");
|
||
assert!(text.contains("字节"), "{text}");
|
||
|
||
let exports = root.join("logs").join("exports");
|
||
let files: Vec<_> = std::fs::read_dir(&exports)
|
||
.expect("导出目录")
|
||
.filter_map(Result::ok)
|
||
.collect();
|
||
assert_eq!(files.len(), 1, "一次导出只该落一个包");
|
||
let size = files[0].metadata().expect("元数据").len();
|
||
assert!(size > 0, "包不该是空文件");
|
||
assert!(
|
||
text.contains(&size.to_string()),
|
||
"报出来的字节数要与磁盘一致:{text} / {size}"
|
||
);
|
||
}
|
||
|
||
/// P3-4:`truncated > 0` 时**界面上那一句**真的出现(r2 复审登记的那条没有用例)。
|
||
///
|
||
/// 抓得住:把 `Exported.text` 里「有文件被截断」那句删掉/短路(变异证明见报告)。
|
||
/// 抓不住:那句话排版好不好看(视觉)。
|
||
#[test]
|
||
fn a_truncated_export_says_so_in_the_notice() {
|
||
use unlucky_core::launch::crash_bundle::MAX_ENTRY_BYTES;
|
||
|
||
let root = std::env::temp_dir().join(format!("ull-m187-trunc-{}", std::process::id()));
|
||
let _ = std::fs::remove_dir_all(&root);
|
||
std::fs::create_dir_all(root.join("logs")).expect("建目录");
|
||
std::fs::create_dir_all(root.join("game").join("logs")).expect("建目录");
|
||
std::fs::write(root.join("logs").join("launcher.log"), "boot\n").expect("写日志");
|
||
|
||
// 略超上限的 latest.log:必须用**真实日志行**填充 —— 同一字符的 4 MiB 会被
|
||
// 「长不透明串」脱敏规则整段替换成占位符,长度就不超限了(那测的是脱敏不是截断)。
|
||
let line = "2026-11-08T15:30:12.441Z [Render thread/INFO]: loading chunk\n";
|
||
let mut big = String::new();
|
||
while big.len() < usize::try_from(MAX_ENTRY_BYTES).expect("常数") + 256 {
|
||
big.push_str(line);
|
||
}
|
||
std::fs::write(root.join("game").join("logs").join("latest.log"), &big).expect("写大日志");
|
||
|
||
let mut report = report(false, Vec::new());
|
||
report.launcher_logs = Some(root.join("logs"));
|
||
report.run_dir = Some(root.join("game"));
|
||
report.session_log = None;
|
||
report.version_json = None;
|
||
|
||
let done = export::export(&report, Lang::ZhCn);
|
||
assert!(done.ok, "{}", done.text);
|
||
assert_eq!(
|
||
done.truncated, 1,
|
||
"这份 latest.log 必须真的被截断(>4 MiB)"
|
||
);
|
||
assert!(
|
||
done.text.contains("已截断"),
|
||
"界面上没有说「有文件被截断」:{}",
|
||
done.text
|
||
);
|
||
}
|