Files
Unlucky-Launcher/crates/core/tests/setting/deprecated_keys.rs
T
AskaEth d517f28140
Release / 选槽位(默认两个 Windows) (push) Canceled after 0s
Release / build (${{ matrix.slot }}) (push) Canceled after 0s
Release / GitHub Release (push) Canceled after 0s
Unlucky Launcher v0.2.1
Single-commit source snapshot of the v0.2.1 release.
2026-11-06 12:35:56 +08:00

143 lines
5.0 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 键废弃机制:`ui.theme` → `appearance.theme_mode`(tower 键冲突裁决)。
//!
//! 规则:**读兼容**(旧值按 `THEME_ALIASES` 映射,新键已在则新键优先)+ **写永远走新键**
//! (`set` 旧键直接报错,落盘不含旧键,AI 白名单与工具 JSON Schema 也不含旧键)。
use serde_json::{json, Value};
use unlucky_core::setting::document::{LoadProblem, SettingDocument};
use unlucky_core::setting::keys::{launcher_schema, LEGACY_THEMES, THEME_ALIASES, THEME_MODES};
use unlucky_core::setting::schema::{SchemaId, SchemaRef, SchemaVersion, SCHEMA_KEY};
use unlucky_core::setting::store::SettingStore;
use crate::common::TempDir;
fn legacy_file(raw_ui: Value) -> Value {
json!({
SCHEMA_KEY: SchemaRef::new(SchemaId::LAUNCHER, SchemaVersion::new(1, 0, 0)).url(),
"ui": raw_ui
})
}
fn deprecated_problem(problems: &[LoadProblem]) -> Option<&'static str> {
problems.iter().find_map(|problem| match problem {
LoadProblem::DeprecatedKey {
key, replaced_by, ..
} if key == "ui.theme" => Some(*replaced_by),
_ => None,
})
}
#[test]
fn legacy_theme_values_are_translated_on_read() {
assert_eq!(THEME_MODES.len(), 3);
assert!(THEME_MODES.contains(&"auto") && THEME_MODES.contains(&"light"));
assert!(THEME_MODES.contains(&"dark"));
assert_eq!(
LEGACY_THEMES.len(),
THEME_ALIASES.len(),
"三个旧值都要有映射"
);
for (legacy, expected) in [
("system", "auto"),
("metro_light", "light"),
("metro_dark", "dark"),
] {
let (doc, problems) =
SettingDocument::load(&launcher_schema(), &legacy_file(json!({ "theme": legacy })));
assert_eq!(
doc.effective_str("appearance.theme_mode"),
Some(expected),
"旧值 {legacy} 应映射成 {expected}"
);
assert_eq!(
doc.legacy_value("ui.theme").and_then(Value::as_str),
Some(legacy),
"旧键原文要留着给 UI 提示/回滚"
);
assert_eq!(deprecated_problem(&problems), Some("appearance.theme_mode"));
assert!(!doc.is_dirty(), "读兼容不算用户改动");
}
}
#[test]
fn new_key_wins_when_both_present() {
let raw = json!({
SCHEMA_KEY: SchemaRef::new(SchemaId::LAUNCHER, SchemaVersion::new(1, 0, 0)).url(),
"ui": { "theme": "metro_dark" },
"appearance": { "theme_mode": "light" }
});
let (doc, _) = SettingDocument::load(&launcher_schema(), &raw);
assert_eq!(doc.effective_str("appearance.theme_mode"), Some("light"));
}
#[test]
fn unmapped_legacy_value_is_reported() {
let (doc, problems) =
SettingDocument::load(&launcher_schema(), &legacy_file(json!({ "theme": "neon" })));
assert_eq!(doc.effective_str("appearance.theme_mode"), Some("neon"));
assert!(
problems.iter().any(|problem| matches!(
problem,
LoadProblem::InvalidValue { key, .. } if key == "appearance.theme_mode"
)),
"映射不过去的旧值要报出来: {problems:?}"
);
}
#[test]
fn writing_the_deprecated_key_is_refused() {
let (mut doc, _) = SettingDocument::load(&launcher_schema(), &json!({}));
let err = doc
.set("ui.theme", json!("metro_dark"))
.expect_err("旧键禁止写");
assert!(err.to_string().contains("appearance.theme_mode"), "{err}");
assert!(!doc.is_dirty());
}
#[test]
fn save_drops_the_old_key_and_writes_the_new_one() {
let temp = TempDir::new("deprecated-save");
temp.write(
"config/launcher.json",
&legacy_file(json!({ "theme": "metro_dark", "language": "en_us" })).to_string(),
);
let mut store = SettingStore::load(temp.child("config/launcher.json"), launcher_schema());
assert_eq!(
store.effective("appearance.theme_mode"),
Some(&json!("dark"))
);
// 随便改一个别的键触发一次保存:旧键消失、新键(映射值)落盘。
store.set("ui.scale", json!(1.25)).expect("改缩放");
store.save().expect("保存");
let saved: Value = serde_json::from_str(&temp.read("config/launcher.json")).expect("JSON 合法");
assert_eq!(saved["appearance"]["theme_mode"], json!("dark"));
assert!(
saved["ui"].get("theme").is_none(),
"废弃键不再落盘: {saved}"
);
assert_eq!(saved["ui"]["language"], json!("en_us"));
}
#[test]
fn whitelist_and_tool_schema_exclude_the_old_key() {
let schema = launcher_schema();
assert_eq!(schema.deprecated_keys(), vec!["ui.theme"]);
assert_eq!(
schema.replacement_of("ui.theme"),
Some("appearance.theme_mode")
);
assert_eq!(schema.replacement_of("appearance.theme_mode"), None);
assert!(!schema.accepts_ai_write("ui.theme"), "废弃键不许 AI 写");
assert!(!schema.ai_writable_keys().contains(&"ui.theme"));
let projected = schema.to_json_schema();
let properties = projected["properties"].as_object().expect("properties");
assert!(properties.contains_key("appearance.theme_mode"));
assert!(!properties.contains_key("ui.theme"));
}