Files
AskaEth bc41dfcf7d
CI / fmt (rustfmt --check) (push) Canceled after 0s
CI / clippy (ubuntu-latest) (push) Canceled after 0s
CI / clippy (windows-latest) (push) Canceled after 0s
CI / test (ubuntu-latest) (push) Canceled after 0s
CI / test (windows-latest) (push) Canceled after 0s
CI / build release (ubuntu-latest) (push) Canceled after 0s
CI / build release (windows-latest) (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Unlucky Launcher v0.0.1-alpha
Rust 原生单文件 Minecraft 启动器:CLI 完整可用(install/launch/accounts/java/diagnose/agent),
MCP server 接入外部 Agent 工具,GUI 开发中。
2026-10-31 21:54:10 +08:00

129 lines
4.0 KiB
Rust

//! 四分区布局、路径拼接、实例 id 白名单、可搬运路径字符串。
use std::path::PathBuf;
use unlucky_core::platform::layout::{
is_valid_instance_id, LauncherLayout, Partition, CONFIG_DIR, GAME_HOME_DIR, INSTANCES_DIR,
LAUNCHER_CONFIG_FILE, LAUNCHER_HOME_DIR, MIGRATION_RECEIPT_FILE, PROFILES_CONFIG_FILE,
REDIRECT_FILE,
};
use crate::common::TempDir;
#[test]
fn home_dir_names_match_design() {
assert_eq!(LAUNCHER_HOME_DIR, ".ULL");
assert_eq!(GAME_HOME_DIR, ".minecraft");
assert_eq!(CONFIG_DIR, "config");
assert_eq!(INSTANCES_DIR, "instances");
assert_eq!(LAUNCHER_CONFIG_FILE, "launcher.json");
assert_eq!(PROFILES_CONFIG_FILE, "profiles.json");
assert_eq!(REDIRECT_FILE, "redirect.json");
assert_eq!(MIGRATION_RECEIPT_FILE, "migration-receipt.json");
}
#[test]
fn exposes_four_partitions() {
let layout = LauncherLayout::new("/home/u/.ULL");
assert_eq!(layout.home(), std::path::Path::new("/home/u/.ULL"));
assert_eq!(layout.config(), PathBuf::from("/home/u/.ULL/config"));
assert_eq!(layout.data(), PathBuf::from("/home/u/.ULL/data"));
assert_eq!(layout.cache(), PathBuf::from("/home/u/.ULL/cache"));
assert_eq!(layout.logs(), PathBuf::from("/home/u/.ULL/logs"));
assert_eq!(Partition::ALL.len(), 4);
assert_eq!(Partition::Config.dir_name(), "config");
assert!(Partition::Cache.is_disposable());
assert!(!Partition::Config.is_disposable());
}
#[test]
fn builds_config_and_cache_paths() {
let layout = LauncherLayout::new("/home/u/.ULL");
assert_eq!(
layout.launcher_config(),
PathBuf::from("/home/u/.ULL/config/launcher.json")
);
assert_eq!(
layout.profiles_config(),
PathBuf::from("/home/u/.ULL/config/profiles.json")
);
assert_eq!(
layout.sha1_cache("ab"),
PathBuf::from("/home/u/.ULL/cache/sha1/ab")
);
assert_eq!(
layout.etag_cache(),
PathBuf::from("/home/u/.ULL/cache/etag.json")
);
assert_eq!(
layout.meta_cache(),
PathBuf::from("/home/u/.ULL/cache/meta")
);
assert_eq!(
layout.java_managed(),
PathBuf::from("/home/u/.ULL/data/java-managed")
);
assert_eq!(layout.auth_data(), PathBuf::from("/home/u/.ULL/data/auth"));
assert_eq!(
layout.agent_sessions(),
PathBuf::from("/home/u/.ULL/data/agent/sessions")
);
assert_eq!(
layout.redirect_path(),
PathBuf::from("/home/u/.ULL/redirect.json")
);
assert_eq!(
layout.migration_receipt(),
PathBuf::from("/home/u/.ULL/config/migration-receipt.json")
);
}
#[test]
fn instance_config_rejects_path_traversal() {
let layout = LauncherLayout::new("/home/u/.ULL");
let id = "6f9619ff-8b86-d011-b42d-00c04fc964ff";
assert!(is_valid_instance_id(id));
assert_eq!(
layout.instance_config(id).expect("合法 id"),
PathBuf::from(format!("/home/u/.ULL/config/instances/{id}.json"))
);
assert!(layout.instance_config("../escape").is_err());
assert!(layout.instance_config("").is_err());
assert!(layout.instance_config("a/b").is_err());
}
#[test]
fn ensure_creates_all_partitions() {
let temp = TempDir::new("layout");
let layout = LauncherLayout::new(temp.child(".ULL"));
layout.ensure().expect("建目录");
for partition in Partition::ALL {
assert!(
layout.partition(partition).is_dir(),
"{}",
partition.as_str()
);
}
}
#[test]
fn portable_path_strings_keep_absolute_and_normalise_relative() {
use unlucky_core::platform::paths::{from_portable_string, to_portable_string};
assert_eq!(
to_portable_string(std::path::Path::new(".minecraft")),
".minecraft"
);
assert_eq!(
to_portable_string(std::path::Path::new("versions\\1.20.1")),
"versions/1.20.1"
);
let absolute = std::env::temp_dir();
assert_eq!(to_portable_string(&absolute), absolute.to_string_lossy());
assert_eq!(
from_portable_string("versions/1.20.1"),
PathBuf::from("versions/1.20.1")
);
}