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 开发中。
122 lines
4.6 KiB
Rust
122 lines
4.6 KiB
Rust
//! 地区判定的单测:只测纯判定与缓存,不真发探测请求。
|
|
|
|
use unlucky_core::download::region::{
|
|
decide_from, load_cached, store_cached, RegionMode, RegionProfile, RegionTrigger, Signals,
|
|
DECISION_TTL_MS, DEFAULT_GH_PROXY,
|
|
};
|
|
|
|
fn signals(timezone: Option<&str>, language: Option<&str>, google: Option<bool>) -> Signals {
|
|
Signals {
|
|
timezone: timezone.map(str::to_string),
|
|
languages: language.map(str::to_string).into_iter().collect(),
|
|
google_reachable: google,
|
|
baidu_reachable: None,
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn timezone_signal_detects_greater_china() {
|
|
assert!(signals(Some("Asia/Shanghai"), None, None).is_greater_china());
|
|
assert!(signals(Some("Asia/Taipei"), None, None).is_greater_china());
|
|
// 大小写/空白容错。
|
|
assert!(signals(Some(" asia/hong_kong "), None, None).is_greater_china());
|
|
assert!(!signals(Some("Europe/Berlin"), None, None).is_greater_china());
|
|
}
|
|
|
|
#[test]
|
|
fn language_signal_handles_posix_and_bcp47() {
|
|
assert!(signals(None, Some("zh_CN.UTF-8"), None).is_greater_china());
|
|
assert!(signals(None, Some("zh-Hant-TW"), None).is_greater_china());
|
|
assert!(!signals(None, Some("en_US.UTF-8"), None).is_greater_china());
|
|
// 时区不命中、语言命中也算。
|
|
assert!(signals(Some("UTC"), Some("zh_TW"), None).is_greater_china());
|
|
}
|
|
|
|
#[test]
|
|
fn domestic_without_google_goes_mirror_first() {
|
|
let profile = decide_from(&signals(Some("Asia/Shanghai"), None, Some(false)), 1);
|
|
assert_eq!(profile.mode, RegionMode::MirrorFirst);
|
|
assert!(profile.greater_china);
|
|
assert_eq!(profile.trigger, RegionTrigger::Auto);
|
|
assert_eq!(profile.gh_proxy.as_deref(), Some(DEFAULT_GH_PROXY));
|
|
assert!(profile.gh_proxy_enabled());
|
|
}
|
|
|
|
#[test]
|
|
fn domestic_with_google_reachable_stays_direct() {
|
|
// 已有全局代理:尊重用户代理,不再插镜像。
|
|
let profile = decide_from(&signals(Some("Asia/Shanghai"), None, Some(true)), 1);
|
|
assert_eq!(profile.mode, RegionMode::Direct);
|
|
assert!(profile.gh_proxy.is_none());
|
|
assert!(!profile.gh_proxy_enabled());
|
|
}
|
|
|
|
#[test]
|
|
fn non_greater_china_is_always_direct() {
|
|
for google in [Some(true), Some(false), None] {
|
|
let profile = decide_from(&signals(Some("America/New_York"), Some("en-US"), google), 1);
|
|
assert_eq!(profile.mode, RegionMode::Direct, "google={google:?}");
|
|
assert!(!profile.greater_china);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn probes_disabled_defaults_to_mirror_first_for_chinese_env() {
|
|
let profile = decide_from(&signals(None, Some("zh_CN.UTF-8"), None), 1);
|
|
assert_eq!(profile.mode, RegionMode::MirrorFirst);
|
|
assert!(!profile.probes_enabled);
|
|
}
|
|
|
|
#[test]
|
|
fn pinned_mode_never_goes_stale() {
|
|
let pinned = RegionProfile::pinned(RegionMode::Direct, 10);
|
|
assert_eq!(pinned.trigger, RegionTrigger::UserPinned);
|
|
assert!(!pinned.is_stale(10 + DECISION_TTL_MS * 10));
|
|
|
|
let auto = decide_from(&signals(Some("Asia/Shanghai"), None, Some(false)), 10);
|
|
assert!(!auto.is_stale(10 + 1_000));
|
|
assert!(auto.is_stale(10 + DECISION_TTL_MS + 1));
|
|
}
|
|
|
|
#[test]
|
|
fn gh_proxy_helpers() {
|
|
let mut profile = RegionProfile::mirror_first(0);
|
|
assert!(profile.gh_proxy_enabled());
|
|
profile = profile.with_gh_proxy(Some(" "));
|
|
assert!(!profile.gh_proxy_enabled(), "空白前缀视为不启用");
|
|
profile = profile.with_gh_proxy(Some("https://proxy.example/"));
|
|
assert!(profile.gh_proxy_enabled());
|
|
|
|
// 直连模式下即便配了前缀也不生效(gh-proxy 只在国内模式用)。
|
|
let direct = RegionProfile::direct(0).with_gh_proxy(Some("https://proxy.example/"));
|
|
assert!(!direct.gh_proxy_enabled());
|
|
assert_eq!(direct.label(), "直连");
|
|
assert_eq!(RegionProfile::mirror_first(0).label(), "镜像优先");
|
|
}
|
|
|
|
#[test]
|
|
fn cache_roundtrip_and_ttl_expiry() {
|
|
let dir = std::env::temp_dir().join(format!("ull-region-{}", std::process::id()));
|
|
let _ = std::fs::remove_dir_all(&dir);
|
|
std::fs::create_dir_all(&dir).unwrap();
|
|
let path = dir.join("region.json");
|
|
|
|
let profile = decide_from(&signals(Some("Asia/Shanghai"), None, Some(false)), 1_000);
|
|
store_cached(&path, &profile).expect("写缓存失败");
|
|
|
|
let cached = load_cached(&path, 1_000 + 60_000).expect("应有缓存");
|
|
assert_eq!(cached, profile);
|
|
|
|
// 过期 → 视为没有缓存。
|
|
assert!(load_cached(&path, 1_000 + DECISION_TTL_MS + 1).is_none());
|
|
|
|
let _ = std::fs::remove_dir_all(&dir);
|
|
}
|
|
|
|
#[test]
|
|
fn missing_cache_file_is_not_an_error() {
|
|
let path = std::env::temp_dir().join("ull-region-does-not-exist.json");
|
|
let _ = std::fs::remove_file(&path);
|
|
assert!(load_cached(&path, 0).is_none());
|
|
}
|