1use serde::{Deserialize, Serialize};
6
7#[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#[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
27pub 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
59pub async fn check_for_updates(current_version: &str) -> Result<UpdateCheckResult, String> {
61 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 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}