Unlucky Launcher v0.0.1-alpha
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

Rust 原生单文件 Minecraft 启动器:CLI 完整可用(install/launch/accounts/java/diagnose/agent),
MCP server 接入外部 Agent 工具,GUI 开发中。
This commit is contained in:
AskaEth committed 2026-10-31 21:54:10 +08:00
commit bc41dfcf7d
517 files changed
+92844

No files matched your search

+109
View File
@@ -0,0 +1,109 @@
//! 实例清单:稳定 UUID、增删查、落盘格式兼容。
use unlucky_core::game::profiles::{
InstanceProfile, ProfileId, ProfileList, PROFILE_SCHEMA_VERSION,
};
#[test]
fn generated_ids_are_unique_and_uuid_shaped() {
let ids: Vec<ProfileId> = (0..256).map(|_| ProfileId::generate()).collect();
for id in &ids {
assert!(id.is_uuid_shaped(), "id 形状不对: {id}");
}
let mut unique: Vec<&str> = ids.iter().map(ProfileId::as_str).collect();
let total = unique.len();
unique.sort_unstable();
unique.dedup();
assert_eq!(unique.len(), total, "同一批生成的 id 不能重复");
}
#[test]
fn id_shape_validation_rejects_junk() {
assert!(!ProfileId::new("not-a-uuid").is_uuid_shaped());
assert!(!ProfileId::new("").is_uuid_shaped());
assert!(ProfileId::new("7c9e6679-7425-40de-944b-e07fc1f90ae7").is_uuid_shaped());
}
#[test]
fn upsert_and_remove_keep_one_entry_per_id() {
let mut list = ProfileList::default();
assert_eq!(list.schema_version, PROFILE_SCHEMA_VERSION);
assert!(list.is_empty());
let mut profile = InstanceProfile::new("主世界", "1.20.1");
assert_eq!(list.upsert(profile.clone()), None, "首次插入没有旧值");
assert_eq!(list.len(), 1);
profile.name = "主世界(Fabric)".to_owned();
let replaced = list.upsert(profile.clone()).expect("同 id 应替换");
assert_eq!(replaced.name, "主世界");
assert_eq!(list.len(), 1);
assert_eq!(
list.get(&profile.id).map(|p| p.name.as_str()),
Some("主世界(Fabric)")
);
let removed = list.remove(&profile.id).expect("应可删除");
assert_eq!(removed.id, profile.id);
assert!(list.is_empty());
assert!(list.remove(&profile.id).is_none());
}
#[test]
fn profiles_group_by_version() {
let mut list = ProfileList::default();
list.upsert(InstanceProfile::new("a", "1.20.1"));
list.upsert(InstanceProfile::new("b", "1.20.1"));
list.upsert(InstanceProfile::new("c", "1.19.4"));
assert_eq!(list.for_version("1.20.1").len(), 2);
assert_eq!(list.for_version("1.19.4").len(), 1);
assert!(list.for_version("1.18.2").is_empty());
}
#[test]
fn roundtrips_profiles_json() {
let mut list = ProfileList::default();
let mut profile = InstanceProfile::new("整合包", "1.20.1-forge-47.2.0");
profile.running_dir = Some(std::path::PathBuf::from("D:/mc/runs/pack"));
profile
.extra
.insert("thirdPartyFlag".to_owned(), serde_json::json!(true));
list.upsert(profile.clone());
let json = list.to_json_string().expect("应可序列化");
let reparsed = ProfileList::from_json_str(&json).expect("应可再解析");
assert_eq!(reparsed, list);
assert_eq!(reparsed.schema_version, PROFILE_SCHEMA_VERSION);
}
#[test]
fn reads_minimal_profile_file() {
// 用户手改/旧版本写下的最小档案:只有三个必填语义字段,其它缺省。
let list = ProfileList::from_json_str(
r#"{ "profiles": [ { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"name": "旧档案", "version_id": "1.12.2" } ] }"#,
)
.expect("最小档案应可解析");
assert_eq!(
list.schema_version, PROFILE_SCHEMA_VERSION,
"schemaVersion 缺省补齐"
);
assert_eq!(list.len(), 1);
let profile = &list.profiles[0];
assert_eq!(profile.name, "旧档案");
assert!(profile.running_dir.is_none());
assert!(profile.id.is_uuid_shaped());
}
#[test]
fn invalid_profiles_json_reports_context() {
let error = ProfileList::from_json_str("{").expect_err("非法 JSON 应报错");
match error {
unlucky_core::game::error::GameError::Json { context, .. } => {
assert_eq!(context, "profiles")
}
other => panic!("期望 Json 错误,得到 {other:?}"),
}
}