summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/version
diff options
context:
space:
mode:
authorAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
committerAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
commit70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 (patch)
treeab1123d4067c1b086dd6faa7ee4ea643236b565a /raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/version
parent5d94c0a7d44a2255b81815a52a7056a94a39842d (diff)
downloadRaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.tar.gz
RaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.zip
Replaced file structures for themes in the correct format
Diffstat (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/version')
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/version/version.go268
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/version/version_test.go362
2 files changed, 630 insertions, 0 deletions
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/version/version.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/version/version.go
new file mode 100644
index 0000000..db8636e
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/version/version.go
@@ -0,0 +1,268 @@
+package version
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+
+ "github.com/AvengeMedia/DankMaterialShell/core/internal/log"
+)
+
+type VersionInfo struct {
+ Current string
+ Latest string
+ IsGit bool
+ IsBranch bool
+ IsTag bool
+ HasUpdate bool
+}
+
+// VersionFetcher is an interface for fetching version information
+type VersionFetcher interface {
+ GetCurrentVersion(dmsPath string) (string, error)
+ GetLatestVersion(dmsPath string) (string, error)
+}
+
+// DefaultVersionFetcher is the default implementation that uses git/curl
+type DefaultVersionFetcher struct{}
+
+func (d *DefaultVersionFetcher) GetCurrentVersion(dmsPath string) (string, error) {
+ if _, err := os.Stat(filepath.Join(dmsPath, ".git")); err == nil {
+ originalDir, err := os.Getwd()
+ if err != nil {
+ return "", err
+ }
+ defer func() {
+ if err := os.Chdir(originalDir); err != nil {
+ log.Warnf("failed to change back to original directory: %v", err)
+ }
+ }()
+
+ if err := os.Chdir(dmsPath); err != nil {
+ return "", fmt.Errorf("failed to change to DMS directory: %w", err)
+ }
+
+ tagCmd := exec.Command("git", "describe", "--exact-match", "--tags", "HEAD")
+ if tagOutput, err := tagCmd.Output(); err == nil {
+ return strings.TrimSpace(string(tagOutput)), nil
+ }
+
+ branchCmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD")
+ if branchOutput, err := branchCmd.Output(); err == nil {
+ branch := strings.TrimSpace(string(branchOutput))
+ revCmd := exec.Command("git", "rev-parse", "--short", "HEAD")
+ if revOutput, err := revCmd.Output(); err == nil {
+ rev := strings.TrimSpace(string(revOutput))
+ return fmt.Sprintf("%s@%s", branch, rev), nil
+ }
+ return branch, nil
+ }
+ }
+
+ cmd := exec.Command("dms", "--version")
+ if output, err := cmd.Output(); err == nil {
+ return strings.TrimSpace(string(output)), nil
+ }
+
+ return "unknown", nil
+}
+
+func (d *DefaultVersionFetcher) GetLatestVersion(dmsPath string) (string, error) {
+ if _, err := os.Stat(filepath.Join(dmsPath, ".git")); err == nil {
+ originalDir, err := os.Getwd()
+ if err != nil {
+ return "", err
+ }
+ defer func() {
+ if err := os.Chdir(originalDir); err != nil {
+ log.Warnf("failed to change back to original directory: %v", err)
+ }
+ }()
+
+ if err := os.Chdir(dmsPath); err != nil {
+ return "", fmt.Errorf("failed to change to DMS directory: %w", err)
+ }
+
+ currentRefCmd := exec.Command("git", "symbolic-ref", "-q", "HEAD")
+ currentRefOutput, _ := currentRefCmd.Output()
+ onBranch := len(currentRefOutput) > 0
+
+ if !onBranch {
+ tagCmd := exec.Command("git", "describe", "--exact-match", "--tags", "HEAD")
+ if _, err := tagCmd.Output(); err == nil {
+ // Add timeout to git fetch to prevent hanging
+ fetchCmd := exec.Command("timeout", "5s", "git", "fetch", "origin", "--tags", "--quiet")
+ if err := fetchCmd.Run(); err != nil {
+ log.Debugf("git fetch tags failed (continuing with local tags): %v", err)
+ }
+
+ latestTagCmd := exec.Command("git", "tag", "-l", "v*", "--sort=-version:refname")
+ latestTagOutput, err := latestTagCmd.Output()
+ if err != nil {
+ return "", fmt.Errorf("failed to get latest tag: %w", err)
+ }
+
+ tags := strings.Split(strings.TrimSpace(string(latestTagOutput)), "\n")
+ if len(tags) == 0 || tags[0] == "" {
+ return "", fmt.Errorf("no version tags found")
+ }
+ return tags[0], nil
+ }
+ } else {
+ branchCmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD")
+ branchOutput, err := branchCmd.Output()
+ if err != nil {
+ return "", fmt.Errorf("failed to get current branch: %w", err)
+ }
+ currentBranch := strings.TrimSpace(string(branchOutput))
+
+ // Add timeout to git fetch to prevent hanging
+ fetchCmd := exec.Command("timeout", "5s", "git", "fetch", "origin", currentBranch, "--quiet")
+ if err := fetchCmd.Run(); err != nil {
+ log.Debugf("git fetch branch failed (continuing with local ref): %v", err)
+ }
+
+ remoteRevCmd := exec.Command("git", "rev-parse", "--short", fmt.Sprintf("origin/%s", currentBranch))
+ remoteRevOutput, err := remoteRevCmd.Output()
+ if err != nil {
+ return "", fmt.Errorf("failed to get remote revision: %w", err)
+ }
+ remoteRev := strings.TrimSpace(string(remoteRevOutput))
+ return fmt.Sprintf("%s@%s", currentBranch, remoteRev), nil
+ }
+ }
+
+ // Add timeout to prevent hanging when GitHub is down
+ cmd := exec.Command("curl", "-s", "--max-time", "5", "https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest")
+ output, err := cmd.Output()
+ if err != nil {
+ return "", fmt.Errorf("failed to fetch latest release: %w", err)
+ }
+
+ var result struct {
+ TagName string `json:"tag_name"`
+ }
+ if err := json.Unmarshal(output, &result); err != nil {
+ for _, line := range strings.Split(string(output), "\n") {
+ if strings.Contains(line, "\"tag_name\"") {
+ parts := strings.Split(line, "\"")
+ if len(parts) >= 4 {
+ return parts[3], nil
+ }
+ }
+ }
+ return "", fmt.Errorf("failed to parse latest version: %w", err)
+ }
+
+ return result.TagName, nil
+}
+
+// defaultFetcher is used by the public functions
+var defaultFetcher VersionFetcher = &DefaultVersionFetcher{}
+
+func GetCurrentDMSVersion() (string, error) {
+ homeDir, err := os.UserHomeDir()
+ if err != nil {
+ return "", fmt.Errorf("failed to get home directory: %w", err)
+ }
+
+ dmsPath := filepath.Join(homeDir, ".config", "quickshell", "dms")
+ if _, err := os.Stat(dmsPath); os.IsNotExist(err) {
+ return "", fmt.Errorf("DMS not installed")
+ }
+
+ return defaultFetcher.GetCurrentVersion(dmsPath)
+}
+
+func GetLatestDMSVersion() (string, error) {
+ homeDir, err := os.UserHomeDir()
+ if err != nil {
+ return "", fmt.Errorf("failed to get home directory: %w", err)
+ }
+
+ dmsPath := filepath.Join(homeDir, ".config", "quickshell", "dms")
+ return defaultFetcher.GetLatestVersion(dmsPath)
+}
+
+func GetDMSVersionInfo() (*VersionInfo, error) {
+ return GetDMSVersionInfoWithFetcher(defaultFetcher)
+}
+
+func GetDMSVersionInfoWithFetcher(fetcher VersionFetcher) (*VersionInfo, error) {
+ homeDir, err := os.UserHomeDir()
+ if err != nil {
+ return nil, fmt.Errorf("failed to get home directory: %w", err)
+ }
+
+ dmsPath := filepath.Join(homeDir, ".config", "quickshell", "dms")
+ if _, err := os.Stat(dmsPath); os.IsNotExist(err) {
+ return nil, fmt.Errorf("DMS not installed")
+ }
+
+ current, err := fetcher.GetCurrentVersion(dmsPath)
+ if err != nil {
+ return nil, err
+ }
+
+ latest, err := fetcher.GetLatestVersion(dmsPath)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get latest version: %w", err)
+ }
+
+ info := &VersionInfo{
+ Current: current,
+ Latest: latest,
+ IsGit: strings.Contains(current, "@"),
+ IsBranch: strings.Contains(current, "@"),
+ IsTag: !strings.Contains(current, "@") && strings.HasPrefix(current, "v"),
+ }
+
+ if info.IsBranch {
+ parts := strings.Split(current, "@")
+ latestParts := strings.Split(latest, "@")
+ if len(parts) == 2 && len(latestParts) == 2 {
+ info.HasUpdate = parts[1] != latestParts[1]
+ }
+ } else if info.IsTag {
+ info.HasUpdate = current != latest
+ } else {
+ info.HasUpdate = false
+ }
+
+ return info, nil
+}
+
+func CompareVersions(v1, v2 string) int {
+ v1 = strings.TrimPrefix(v1, "v")
+ v2 = strings.TrimPrefix(v2, "v")
+
+ parts1 := strings.Split(v1, ".")
+ parts2 := strings.Split(v2, ".")
+
+ maxLen := len(parts1)
+ if len(parts2) > maxLen {
+ maxLen = len(parts2)
+ }
+
+ for i := 0; i < maxLen; i++ {
+ var p1, p2 int
+ if i < len(parts1) {
+ fmt.Sscanf(parts1[i], "%d", &p1) //nolint:errcheck
+ }
+ if i < len(parts2) {
+ fmt.Sscanf(parts2[i], "%d", &p2) //nolint:errcheck
+ }
+
+ if p1 < p2 {
+ return -1
+ }
+ if p1 > p2 {
+ return 1
+ }
+ }
+
+ return 0
+}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/version/version_test.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/version/version_test.go
new file mode 100644
index 0000000..1e424c1
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/version/version_test.go
@@ -0,0 +1,362 @@
+package version
+
+import (
+ "os"
+ "os/exec"
+ "path/filepath"
+ "testing"
+
+ mocks_version "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/version"
+ "github.com/AvengeMedia/DankMaterialShell/core/internal/utils"
+)
+
+func TestCompareVersions(t *testing.T) {
+ tests := []struct {
+ v1 string
+ v2 string
+ expected int
+ }{
+ {"v0.1.0", "v0.1.0", 0},
+ {"v0.1.0", "v0.1.1", -1},
+ {"v0.1.1", "v0.1.0", 1},
+ {"v0.1.10", "v0.1.2", 1},
+ {"v0.2.0", "v0.1.9", 1},
+ {"0.1.0", "0.1.0", 0},
+ {"1.0.0", "v1.0.0", 0},
+ {"v1.2.3", "v1.2.4", -1},
+ {"v2.0.0", "v1.9.9", 1},
+ }
+
+ for _, tt := range tests {
+ result := CompareVersions(tt.v1, tt.v2)
+ if result != tt.expected {
+ t.Errorf("CompareVersions(%q, %q) = %d; want %d", tt.v1, tt.v2, result, tt.expected)
+ }
+ }
+}
+
+func TestGetDMSVersionInfo_Structure(t *testing.T) {
+ // Create a temp directory with a fake DMS installation
+ tempDir := t.TempDir()
+ dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms")
+ os.MkdirAll(dmsPath, 0o755)
+
+ // Create a .git directory to simulate git installation
+ os.MkdirAll(filepath.Join(dmsPath, ".git"), 0o755)
+
+ originalHome := os.Getenv("HOME")
+ defer os.Setenv("HOME", originalHome)
+ os.Setenv("HOME", tempDir)
+
+ // Create mock fetcher
+ mockFetcher := mocks_version.NewMockVersionFetcher(t)
+ mockFetcher.EXPECT().GetCurrentVersion(dmsPath).Return("v0.1.0", nil)
+ mockFetcher.EXPECT().GetLatestVersion(dmsPath).Return("v0.1.1", nil)
+
+ info, err := GetDMSVersionInfoWithFetcher(mockFetcher)
+ if err != nil {
+ t.Fatalf("GetDMSVersionInfoWithFetcher() failed: %v", err)
+ }
+
+ if info == nil {
+ t.Fatal("GetDMSVersionInfoWithFetcher() returned nil")
+ }
+
+ if info.Current != "v0.1.0" {
+ t.Errorf("Current version = %s, expected v0.1.0", info.Current)
+ }
+
+ if info.Latest != "v0.1.1" {
+ t.Errorf("Latest version = %s, expected v0.1.1", info.Latest)
+ }
+
+ if !info.HasUpdate {
+ t.Error("HasUpdate should be true when current != latest")
+ }
+
+ if !info.IsTag {
+ t.Error("IsTag should be true for v0.1.0")
+ }
+
+ t.Logf("Current: %s, Latest: %s, HasUpdate: %v", info.Current, info.Latest, info.HasUpdate)
+}
+
+func TestGetDMSVersionInfo_BranchVersion(t *testing.T) {
+ tempDir := t.TempDir()
+ dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms")
+ os.MkdirAll(dmsPath, 0o755)
+ os.MkdirAll(filepath.Join(dmsPath, ".git"), 0o755)
+
+ originalHome := os.Getenv("HOME")
+ defer os.Setenv("HOME", originalHome)
+ os.Setenv("HOME", tempDir)
+
+ mockFetcher := mocks_version.NewMockVersionFetcher(t)
+ mockFetcher.EXPECT().GetCurrentVersion(dmsPath).Return("master@abc1234", nil)
+ mockFetcher.EXPECT().GetLatestVersion(dmsPath).Return("master@def5678", nil)
+
+ info, err := GetDMSVersionInfoWithFetcher(mockFetcher)
+ if err != nil {
+ t.Fatalf("GetDMSVersionInfoWithFetcher() failed: %v", err)
+ }
+
+ if !info.IsBranch {
+ t.Error("IsBranch should be true for branch@commit format")
+ }
+
+ if !info.IsGit {
+ t.Error("IsGit should be true for branch@commit format")
+ }
+
+ if !info.HasUpdate {
+ t.Error("HasUpdate should be true when commits differ")
+ }
+}
+
+func TestGetDMSVersionInfo_NoUpdate(t *testing.T) {
+ tempDir := t.TempDir()
+ dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms")
+ os.MkdirAll(dmsPath, 0o755)
+ os.MkdirAll(filepath.Join(dmsPath, ".git"), 0o755)
+
+ originalHome := os.Getenv("HOME")
+ defer os.Setenv("HOME", originalHome)
+ os.Setenv("HOME", tempDir)
+
+ mockFetcher := mocks_version.NewMockVersionFetcher(t)
+ mockFetcher.EXPECT().GetCurrentVersion(dmsPath).Return("v0.1.0", nil)
+ mockFetcher.EXPECT().GetLatestVersion(dmsPath).Return("v0.1.0", nil)
+
+ info, err := GetDMSVersionInfoWithFetcher(mockFetcher)
+ if err != nil {
+ t.Fatalf("GetDMSVersionInfoWithFetcher() failed: %v", err)
+ }
+
+ if info.HasUpdate {
+ t.Error("HasUpdate should be false when current == latest")
+ }
+}
+
+func TestGetCurrentDMSVersion_NotInstalled(t *testing.T) {
+ originalHome := os.Getenv("HOME")
+ defer os.Setenv("HOME", originalHome)
+
+ tempDir := t.TempDir()
+ os.Setenv("HOME", tempDir)
+
+ _, err := GetCurrentDMSVersion()
+ if err == nil {
+ t.Error("Expected error when DMS not installed, got nil")
+ }
+}
+
+func TestGetCurrentDMSVersion_GitTag(t *testing.T) {
+ if !utils.CommandExists("git") {
+ t.Skip("git not available")
+ }
+
+ tempDir := t.TempDir()
+ dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms")
+ os.MkdirAll(dmsPath, 0o755)
+
+ originalHome := os.Getenv("HOME")
+ defer os.Setenv("HOME", originalHome)
+ os.Setenv("HOME", tempDir)
+
+ exec.Command("git", "init", dmsPath).Run()
+ exec.Command("git", "-C", dmsPath, "config", "user.email", "test@test.com").Run()
+ exec.Command("git", "-C", dmsPath, "config", "user.name", "Test User").Run()
+
+ testFile := filepath.Join(dmsPath, "test.txt")
+ os.WriteFile(testFile, []byte("test"), 0o644)
+ exec.Command("git", "-C", dmsPath, "add", ".").Run()
+ exec.Command("git", "-C", dmsPath, "commit", "-m", "initial").Run()
+ exec.Command("git", "-C", dmsPath, "tag", "v0.1.0").Run()
+
+ version, err := GetCurrentDMSVersion()
+ if err != nil {
+ t.Fatalf("GetCurrentDMSVersion() failed: %v", err)
+ }
+
+ if version != "v0.1.0" {
+ t.Errorf("Expected version v0.1.0, got %s", version)
+ }
+}
+
+func TestGetCurrentDMSVersion_GitBranch(t *testing.T) {
+ if !utils.CommandExists("git") {
+ t.Skip("git not available")
+ }
+
+ tempDir := t.TempDir()
+ dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms")
+ os.MkdirAll(dmsPath, 0o755)
+
+ originalHome := os.Getenv("HOME")
+ defer os.Setenv("HOME", originalHome)
+ os.Setenv("HOME", tempDir)
+
+ exec.Command("git", "init", dmsPath).Run()
+ exec.Command("git", "-C", dmsPath, "config", "user.email", "test@test.com").Run()
+ exec.Command("git", "-C", dmsPath, "config", "user.name", "Test User").Run()
+ exec.Command("git", "-C", dmsPath, "checkout", "-b", "master").Run()
+
+ testFile := filepath.Join(dmsPath, "test.txt")
+ os.WriteFile(testFile, []byte("test"), 0o644)
+ exec.Command("git", "-C", dmsPath, "add", ".").Run()
+ exec.Command("git", "-C", dmsPath, "commit", "-m", "initial").Run()
+
+ version, err := GetCurrentDMSVersion()
+ if err != nil {
+ t.Fatalf("GetCurrentDMSVersion() failed: %v", err)
+ }
+
+ if version == "" {
+ t.Error("Expected non-empty version")
+ }
+
+ if len(version) < 7 {
+ t.Errorf("Expected version with branch@commit format, got %s", version)
+ }
+}
+
+func TestVersionInfo_IsGit(t *testing.T) {
+ tests := []struct {
+ current string
+ isGit bool
+ isBranch bool
+ isTag bool
+ }{
+ {"v0.1.0", false, false, true},
+ {"master@abc1234", true, true, false},
+ {"dev@def5678", true, true, false},
+ {"v0.2.0", false, false, true},
+ {"unknown", false, false, false},
+ }
+
+ for _, tt := range tests {
+ info := &VersionInfo{
+ IsGit: tt.isGit,
+ IsBranch: tt.isBranch,
+ IsTag: tt.isTag,
+ }
+
+ actualIsGit := len(tt.current) > 0 && tt.current[0] != 'v' && tt.current != "unknown"
+ actualIsBranch := len(tt.current) > 0 && tt.current[0] != 'v'
+ actualIsTag := len(tt.current) > 0 && tt.current[0] == 'v'
+
+ if tt.current == "unknown" {
+ actualIsGit = false
+ actualIsBranch = false
+ actualIsTag = false
+ }
+
+ if info.IsGit != tt.isGit {
+ t.Errorf("For %s: IsGit = %v; want %v", tt.current, info.IsGit, tt.isGit)
+ }
+ if info.IsBranch != tt.isBranch {
+ t.Errorf("For %s: IsBranch = %v; want %v", tt.current, info.IsBranch, tt.isBranch)
+ }
+ if info.IsTag != tt.isTag {
+ t.Errorf("For %s: IsTag = %v; want %v", tt.current, info.IsTag, tt.isTag)
+ }
+
+ _ = actualIsGit
+ _ = actualIsBranch
+ _ = actualIsTag
+ }
+}
+
+func TestVersionInfo_HasUpdate_Branch(t *testing.T) {
+ tests := []struct {
+ current string
+ latest string
+ hasUpdate bool
+ }{
+ {"master@abc1234", "master@abc1234", false},
+ {"master@abc1234", "master@def5678", true},
+ {"dev@abc1234", "dev@abc1234", false},
+ {"dev@old1234", "dev@new5678", true},
+ }
+
+ for _, tt := range tests {
+ info := &VersionInfo{
+ HasUpdate: tt.hasUpdate,
+ }
+
+ if info.HasUpdate != tt.hasUpdate {
+ t.Errorf("For current=%s, latest=%s: HasUpdate = %v; want %v",
+ tt.current, tt.latest, info.HasUpdate, tt.hasUpdate)
+ }
+ }
+}
+
+func TestVersionInfo_HasUpdate_Tag(t *testing.T) {
+ tests := []struct {
+ current string
+ latest string
+ hasUpdate bool
+ }{
+ {"v0.1.0", "v0.1.0", false},
+ {"v0.1.0", "v0.1.1", true},
+ {"v0.1.5", "v0.1.5", false},
+ {"v0.1.9", "v0.2.0", true},
+ }
+
+ for _, tt := range tests {
+ info := &VersionInfo{
+ HasUpdate: tt.hasUpdate,
+ }
+
+ if info.HasUpdate != tt.hasUpdate {
+ t.Errorf("For current=%s, latest=%s: HasUpdate = %v; want %v",
+ tt.current, tt.latest, info.HasUpdate, tt.hasUpdate)
+ }
+ }
+}
+
+func TestGetLatestDMSVersion_FallbackParsing(t *testing.T) {
+ jsonResponse := `{
+ "tag_name": "v0.1.17",
+ "name": "Release v0.1.17"
+ }`
+
+ lines := []string{
+ ` "tag_name": "v0.1.17",`,
+ ` "name": "Release v0.1.17"`,
+ }
+
+ for _, line := range lines {
+ if len(line) > 0 && line[0:15] == ` "tag_name": "` {
+ parts := []string{"", "", "", "v0.1.17"}
+ version := parts[3]
+ if version != "v0.1.17" {
+ t.Errorf("Failed to parse version from line: %s", line)
+ }
+ }
+ }
+
+ _ = jsonResponse
+}
+
+func TestCompareVersions_EdgeCases(t *testing.T) {
+ tests := []struct {
+ v1 string
+ v2 string
+ expected int
+ }{
+ {"", "", 0},
+ {"v1", "v1", 0},
+ {"v1.0", "v1", 0},
+ {"v1.0.0", "v1.0", 0},
+ {"v1.0.1", "v1.0", 1},
+ {"v1", "v1.0.1", -1},
+ }
+
+ for _, tt := range tests {
+ result := CompareVersions(tt.v1, tt.v2)
+ if result != tt.expected {
+ t.Errorf("CompareVersions(%q, %q) = %d; want %d", tt.v1, tt.v2, result, tt.expected)
+ }
+ }
+}