Skip to main content

aster/updater/
checker.rs

1//! 版本检查器
2//!
3//! 提供版本检查和比较功能
4
5use serde::{Deserialize, Serialize};
6
7/// 版本信息
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct VersionInfo {
10    pub version: String,
11    pub release_date: String,
12    pub changelog: Option<String>,
13    pub download_url: Option<String>,
14    pub description: Option<String>,
15}
16
17/// 更新检查结果
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct UpdateCheckResult {
20    pub has_update: bool,
21    pub current_version: String,
22    pub latest_version: String,
23    pub version_info: Option<VersionInfo>,
24    pub changelog: Option<Vec<String>>,
25}
26
27/// 比较版本号
28/// 返回: 1 表示 v1 > v2, -1 表示 v1 < v2, 0 表示相等
29pub fn compare_versions(v1: &str, v2: &str) -> i32 {
30    let parse_version = |v: &str| -> Vec<u32> {
31        v.chars()
32            .filter(|c| c.is_ascii_digit() || *c == '.')
33            .collect::<String>()
34            .split('.')
35            .filter_map(|s| s.parse().ok())
36            .collect()
37    };
38
39    let parts1 = parse_version(v1);
40    let parts2 = parse_version(v2);
41
42    let max_len = parts1.len().max(parts2.len());
43
44    for i in 0..max_len {
45        let p1 = parts1.get(i).copied().unwrap_or(0);
46        let p2 = parts2.get(i).copied().unwrap_or(0);
47
48        if p1 > p2 {
49            return 1;
50        }
51        if p1 < p2 {
52            return -1;
53        }
54    }
55
56    0
57}
58
59/// 检查更新(简化实现)
60pub async fn check_for_updates(current_version: &str) -> Result<UpdateCheckResult, String> {
61    // 实际实现需要从远程获取最新版本
62    // 这里返回一个模拟结果
63    Ok(UpdateCheckResult {
64        has_update: false,
65        current_version: current_version.to_string(),
66        latest_version: current_version.to_string(),
67        version_info: None,
68        changelog: None,
69    })
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn test_compare_versions() {
78        assert_eq!(compare_versions("1.0.0", "1.0.0"), 0);
79        assert_eq!(compare_versions("1.0.1", "1.0.0"), 1);
80        assert_eq!(compare_versions("1.0.0", "1.0.1"), -1);
81        assert_eq!(compare_versions("2.0.0", "1.9.9"), 1);
82        assert_eq!(compare_versions("1.10.0", "1.9.0"), 1);
83        assert_eq!(compare_versions("v1.0.0", "1.0.0"), 0);
84    }
85}
86
87#[test]
88fn test_compare_versions_with_prerelease() {
89    // 简化实现忽略预发布标签,只比较数字部分
90    assert_eq!(compare_versions("1.0.0-beta", "1.0.0"), 0);
91    assert_eq!(compare_versions("1.0.0", "1.0.0-alpha"), 0);
92}
93
94#[test]
95fn test_compare_versions_different_lengths() {
96    assert_eq!(compare_versions("1.0", "1.0.0"), 0);
97    assert_eq!(compare_versions("1.0.0.1", "1.0.0"), 1);
98}
99
100#[test]
101fn test_version_info_struct() {
102    let info = VersionInfo {
103        version: "1.0.0".to_string(),
104        release_date: "2026-01-14".to_string(),
105        changelog: Some("Initial release".to_string()),
106        download_url: Some("https://example.com/v1.0.0".to_string()),
107        description: Some("Test version".to_string()),
108    };
109    assert_eq!(info.version, "1.0.0");
110    assert!(info.changelog.is_some());
111}
112
113#[test]
114fn test_update_check_result_struct() {
115    let result = UpdateCheckResult {
116        has_update: true,
117        current_version: "1.0.0".to_string(),
118        latest_version: "1.1.0".to_string(),
119        version_info: None,
120        changelog: Some(vec!["Fix bug".to_string()]),
121    };
122    assert!(result.has_update);
123    assert_eq!(result.current_version, "1.0.0");
124    assert_eq!(result.latest_version, "1.1.0");
125}
126
127#[tokio::test]
128async fn test_check_for_updates_async() {
129    let result = check_for_updates("1.0.0").await;
130    assert!(result.is_ok());
131    let check = result.unwrap();
132    assert_eq!(check.current_version, "1.0.0");
133}