package updater import ( "encoding/json" "net/http" "net/http/httptest" "testing" ) func TestNewUpdateService(t *testing.T) { svc := NewUpdateService("0.2.0") if svc.currentVersion != "0.2.0" { t.Errorf("currentVersion = %q, want %q", svc.currentVersion, "0.2.0") } if svc.baseURL == "" { t.Error("baseURL should not be empty") } if svc.owner == "" { t.Error("owner should not be empty") } if svc.pkg == "" { t.Error("pkg should not be empty") } if svc.httpClient == nil { t.Error("httpClient should not be nil") } } func TestNewUpdateServiceStripsVPrefix(t *testing.T) { svc := NewUpdateService("v1.2.3") if svc.currentVersion != "1.2.3" { t.Errorf("currentVersion = %q, want %q", svc.currentVersion, "1.2.3") } } func TestCompareVersions(t *testing.T) { tests := []struct { a, b string want int }{ {"0.2.0", "0.2.1", -1}, {"0.2.1", "0.2.0", 1}, {"0.3.0", "0.2.9", 1}, {"0.2.9", "0.3.0", -1}, {"1.0.0", "0.9.9", 1}, {"0.9.9", "1.0.0", -1}, {"1.0.0", "1.0.0", 0}, {"0.0.1", "0.0.1", 0}, {"2.0.0", "1.99.99", 1}, {"0.1.0", "0.0.99", 1}, // With "v" prefix {"v0.2.0", "v0.2.1", -1}, {"v1.0.0", "1.0.0", 0}, } for _, tt := range tests { got := CompareVersions(tt.a, tt.b) if got != tt.want { t.Errorf("CompareVersions(%q, %q) = %d, want %d", tt.a, tt.b, got, tt.want) } } } func TestParseSemver(t *testing.T) { tests := []struct { input string want [3]int }{ {"1.2.3", [3]int{1, 2, 3}}, {"0.0.0", [3]int{0, 0, 0}}, {"10.20.30", [3]int{10, 20, 30}}, {"1.2", [3]int{1, 2, 0}}, {"1", [3]int{1, 0, 0}}, {"", [3]int{0, 0, 0}}, } for _, tt := range tests { got := parseSemver(tt.input) if got != tt.want { t.Errorf("parseSemver(%q) = %v, want %v", tt.input, got, tt.want) } } } func TestParseVersionJSON(t *testing.T) { raw := `{"version":"0.3.0","sha256":"abcdef1234567890","downloadUrl":"https://example.com/setup.exe"}` var v versionJSON if err := json.Unmarshal([]byte(raw), &v); err != nil { t.Fatalf("Unmarshal error: %v", err) } if v.Version != "0.3.0" { t.Errorf("Version = %q, want %q", v.Version, "0.3.0") } if v.SHA256 != "abcdef1234567890" { t.Errorf("SHA256 = %q, want %q", v.SHA256, "abcdef1234567890") } if v.DownloadURL != "https://example.com/setup.exe" { t.Errorf("DownloadURL = %q, want %q", v.DownloadURL, "https://example.com/setup.exe") } } func TestCheckForUpdate_NewerAvailable(t *testing.T) { // Mock the Gitea API: return a single package version that is newer. mux := http.NewServeMux() mux.HandleFunc("/api/v1/packages/vstockwell/generic/wraith", func(w http.ResponseWriter, r *http.Request) { versions := []giteaPackageVersion{{Version: "0.3.0"}} w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(versions) }) mux.HandleFunc("/api/packages/vstockwell/generic/wraith/0.3.0/version.json", func(w http.ResponseWriter, r *http.Request) { v := versionJSON{ Version: "0.3.0", SHA256: "abc123", DownloadURL: "https://example.com/wraith-0.3.0-setup.exe", } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(v) }) server := httptest.NewServer(mux) defer server.Close() svc := NewUpdateService("0.2.0") svc.baseURL = server.URL info, err := svc.CheckForUpdate() if err != nil { t.Fatalf("CheckForUpdate() error: %v", err) } if !info.Available { t.Error("expected Available = true") } if info.LatestVer != "0.3.0" { t.Errorf("LatestVer = %q, want %q", info.LatestVer, "0.3.0") } if info.SHA256 != "abc123" { t.Errorf("SHA256 = %q, want %q", info.SHA256, "abc123") } if info.DownloadURL != "https://example.com/wraith-0.3.0-setup.exe" { t.Errorf("DownloadURL = %q, want %q", info.DownloadURL, "https://example.com/wraith-0.3.0-setup.exe") } } func TestCheckForUpdate_AlreadyUpToDate(t *testing.T) { mux := http.NewServeMux() mux.HandleFunc("/api/v1/packages/vstockwell/generic/wraith", func(w http.ResponseWriter, r *http.Request) { versions := []giteaPackageVersion{{Version: "0.2.0"}} w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(versions) }) server := httptest.NewServer(mux) defer server.Close() svc := NewUpdateService("0.2.0") svc.baseURL = server.URL info, err := svc.CheckForUpdate() if err != nil { t.Fatalf("CheckForUpdate() error: %v", err) } if info.Available { t.Error("expected Available = false (same version)") } } func TestCheckForUpdate_CurrentIsNewer(t *testing.T) { mux := http.NewServeMux() mux.HandleFunc("/api/v1/packages/vstockwell/generic/wraith", func(w http.ResponseWriter, r *http.Request) { versions := []giteaPackageVersion{{Version: "0.1.0"}} w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(versions) }) server := httptest.NewServer(mux) defer server.Close() svc := NewUpdateService("0.2.0") svc.baseURL = server.URL info, err := svc.CheckForUpdate() if err != nil { t.Fatalf("CheckForUpdate() error: %v", err) } if info.Available { t.Error("expected Available = false (current is newer)") } } func TestCheckForUpdate_NoVersions(t *testing.T) { mux := http.NewServeMux() mux.HandleFunc("/api/v1/packages/vstockwell/generic/wraith", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode([]giteaPackageVersion{}) }) server := httptest.NewServer(mux) defer server.Close() svc := NewUpdateService("0.2.0") svc.baseURL = server.URL info, err := svc.CheckForUpdate() if err != nil { t.Fatalf("CheckForUpdate() error: %v", err) } if info.Available { t.Error("expected Available = false (no versions)") } } func TestCheckForUpdate_APIError(t *testing.T) { mux := http.NewServeMux() mux.HandleFunc("/api/v1/packages/vstockwell/generic/wraith", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) }) server := httptest.NewServer(mux) defer server.Close() svc := NewUpdateService("0.2.0") svc.baseURL = server.URL _, err := svc.CheckForUpdate() if err == nil { t.Error("expected error from API failure") } }