mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-07-22 01:15:14 +08:00
fix(adapters): 按数值比较 Unity 版本范围
VersionRange::contains 原为字符串字典序比较,2021.3.9f1 等带发布后缀的 正式版本会被 can_handle/parse 误拒,多位补丁号排序也不正确。改为解析 (major, minor, patch) 数值元组比较,补丁号剥离发布后缀,无法解析的版本 一律视为不在范围内,并补充多位补丁号、后缀版本和畸形版本的测试。 对应 issue #18 维护清单 1-1。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,10 +21,40 @@ impl VersionRange {
|
||||
}
|
||||
|
||||
/// 检查版本是否在范围内
|
||||
///
|
||||
/// 按 `(major, minor, patch)` 数值比较,补丁号允许携带 Unity 发布后缀
|
||||
/// (例如 `2021.3.9f1` 按补丁号 9 参与比较);无法解析的版本一律视为不在范围内。
|
||||
pub fn contains(&self, version: &str) -> bool {
|
||||
version >= self.min.as_str() && version <= self.max.as_str()
|
||||
match (
|
||||
parse_version_components(version),
|
||||
parse_version_components(&self.min),
|
||||
parse_version_components(&self.max),
|
||||
) {
|
||||
(Some(version), Some(min), Some(max)) => version >= min && version <= max,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 将 Unity 版本字符串解析为 `(major, minor, patch)` 数值元组。
|
||||
///
|
||||
/// `major`/`minor` 必须是纯数字;`patch` 取第三段的前导数字,
|
||||
/// 以兼容 `2021.3.9f1` 这类带发布后缀的正式版本号。
|
||||
fn parse_version_components(version: &str) -> Option<(u64, u64, u64)> {
|
||||
let mut parts = version.split('.');
|
||||
let major = parts.next()?.parse::<u64>().ok()?;
|
||||
let minor = parts.next()?.parse::<u64>().ok()?;
|
||||
let patch_part = parts.next()?;
|
||||
let digit_count = patch_part
|
||||
.chars()
|
||||
.take_while(|character| character.is_ascii_digit())
|
||||
.count();
|
||||
if digit_count == 0 {
|
||||
return None;
|
||||
}
|
||||
let patch = patch_part[..digit_count].parse::<u64>().ok()?;
|
||||
Some((major, minor, patch))
|
||||
}
|
||||
|
||||
/// 原始 AssetBundle 数据
|
||||
#[derive(Debug)]
|
||||
@@ -175,6 +205,40 @@ mod tests {
|
||||
assert!(!range.contains("2021.4.0"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version_range_compares_patch_numerically() {
|
||||
let range = VersionRange::new("2021.3.0", "2021.3.99");
|
||||
|
||||
assert!(!range.contains("2021.3.100"));
|
||||
assert!(range.contains("2021.3.9"));
|
||||
|
||||
let wide_range = VersionRange::new("2021.3.20", "2021.3.120");
|
||||
assert!(wide_range.contains("2021.3.100"));
|
||||
assert!(!wide_range.contains("2021.3.9"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version_range_accepts_release_suffix() {
|
||||
let range = VersionRange::new("2021.3.0", "2021.3.99");
|
||||
|
||||
assert!(range.contains("2021.3.9f1"));
|
||||
assert!(range.contains("2021.3.56f2"));
|
||||
assert!(range.contains("2021.3.99f1"));
|
||||
assert!(!range.contains("2021.3.100f1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version_range_rejects_malformed_versions() {
|
||||
let range = VersionRange::new("2021.3.0", "2021.3.99");
|
||||
|
||||
assert!(!range.contains(""));
|
||||
assert!(!range.contains("unknown"));
|
||||
assert!(!range.contains("2021"));
|
||||
assert!(!range.contains("2021.3"));
|
||||
assert!(!range.contains("2021.x.5"));
|
||||
assert!(!range.contains("2021.3.f1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_assetbundle() {
|
||||
let bundle = RawAssetBundle {
|
||||
|
||||
@@ -436,6 +436,7 @@ mod tests {
|
||||
|
||||
assert!(range.contains("2021.3.0"));
|
||||
assert!(range.contains("2021.3.56"));
|
||||
assert!(range.contains("2021.3.9f1"));
|
||||
assert!(!range.contains("2021.2.0"));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user