package download import ( "archive/zip" "crypto/sha256" "encoding/hex" "os" "path/filepath" "testing" ) func TestHashFileToHex_KnownContent(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "testfile.bin") content := []byte("hello world") if err := os.WriteFile(path, content, 0644); err != nil { t.Fatalf("failed to write temp file: %v", err) } got := hashFileToHex(path) h := sha256.Sum256(content) want := hex.EncodeToString(h[:]) if got != want { t.Errorf("hashFileToHex = %q, want %q", got, want) } } func TestHashFileToHex_EmptyFile(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "empty.bin") if err := os.WriteFile(path, []byte{}, 0644); err != nil { t.Fatalf("failed to write temp file: %v", err) } got := hashFileToHex(path) h := sha256.Sum256([]byte{}) want := hex.EncodeToString(h[:]) if got != want { t.Errorf("hashFileToHex (empty) = %q, want %q", got, want) } } func TestHashFileToHex_NonExistentFile(t *testing.T) { got := hashFileToHex("/nonexistent/path/file.bin") if got != "" { t.Errorf("hashFileToHex (nonexistent) = %q, want empty string", got) } } // createTestZip creates a zip file at zipPath containing the given files. // files is a map of filename -> content. func createTestZip(t *testing.T, zipPath string, files map[string][]byte) { t.Helper() f, err := os.Create(zipPath) if err != nil { t.Fatalf("failed to create zip: %v", err) } defer f.Close() w := zip.NewWriter(f) for name, data := range files { fw, err := w.Create(name) if err != nil { t.Fatalf("failed to create zip entry %s: %v", name, err) } if _, err := fw.Write(data); err != nil { t.Fatalf("failed to write zip entry %s: %v", name, err) } } if err := w.Close(); err != nil { t.Fatalf("failed to close zip writer: %v", err) } } func TestHashGameExeFromZip_WithA301Exe(t *testing.T) { dir := t.TempDir() zipPath := filepath.Join(dir, "game.zip") exeContent := []byte("fake A301.exe binary content for testing") createTestZip(t, zipPath, map[string][]byte{ "GameFolder/A301.exe": exeContent, "GameFolder/readme.txt": []byte("readme"), }) got := hashGameExeFromZip(zipPath) h := sha256.Sum256(exeContent) want := hex.EncodeToString(h[:]) if got != want { t.Errorf("hashGameExeFromZip = %q, want %q", got, want) } } func TestHashGameExeFromZip_CaseInsensitive(t *testing.T) { dir := t.TempDir() zipPath := filepath.Join(dir, "game.zip") exeContent := []byte("case insensitive test") createTestZip(t, zipPath, map[string][]byte{ "build/a301.EXE": exeContent, }) got := hashGameExeFromZip(zipPath) h := sha256.Sum256(exeContent) want := hex.EncodeToString(h[:]) if got != want { t.Errorf("hashGameExeFromZip (case insensitive) = %q, want %q", got, want) } } func TestHashGameExeFromZip_NoA301Exe(t *testing.T) { dir := t.TempDir() zipPath := filepath.Join(dir, "game.zip") createTestZip(t, zipPath, map[string][]byte{ "GameFolder/other.exe": []byte("not A301"), "GameFolder/readme.txt": []byte("readme"), }) got := hashGameExeFromZip(zipPath) if got != "" { t.Errorf("hashGameExeFromZip (no A301.exe) = %q, want empty string", got) } } func TestHashGameExeFromZip_EmptyZip(t *testing.T) { dir := t.TempDir() zipPath := filepath.Join(dir, "empty.zip") createTestZip(t, zipPath, map[string][]byte{}) got := hashGameExeFromZip(zipPath) if got != "" { t.Errorf("hashGameExeFromZip (empty zip) = %q, want empty string", got) } } func TestHashGameExeFromZip_InvalidZip(t *testing.T) { dir := t.TempDir() zipPath := filepath.Join(dir, "notazip.zip") if err := os.WriteFile(zipPath, []byte("this is not a zip file"), 0644); err != nil { t.Fatalf("failed to write file: %v", err) } got := hashGameExeFromZip(zipPath) if got != "" { t.Errorf("hashGameExeFromZip (invalid zip) = %q, want empty string", got) } } func TestVersionRegex(t *testing.T) { tests := []struct { input string want string }{ {"game_v1.2.3.zip", "v1.2.3"}, {"game_v2.0.zip", "v2.0"}, {"game_v10.20.30.zip", "v10.20.30"}, {"game.zip", ""}, {"noversion", ""}, } for _, tt := range tests { got := versionRe.FindString(tt.input) if got != tt.want { t.Errorf("versionRe.FindString(%q) = %q, want %q", tt.input, got, tt.want) } } } func TestGameFilePath(t *testing.T) { s := NewService(nil, "/data/game") got := s.GameFilePath() // filepath.Join normalizes separators per OS want := filepath.Join("/data/game", "game.zip") if got != want { t.Errorf("GameFilePath() = %q, want %q", got, want) } } func TestLauncherFilePath(t *testing.T) { s := NewService(nil, "/data/game") got := s.LauncherFilePath() want := filepath.Join("/data/game", "launcher.exe") if got != want { t.Errorf("LauncherFilePath() = %q, want %q", got, want) } }