package main import ( "os" "path/filepath" "testing" "time" ) func TestIsCacheEntryExpired(t *testing.T) { if isCacheEntryExpired(time.Now().Add(-24*time.Hour), 0) { t.Fatalf("expected ttl=0 to disable expiration") } if !isCacheEntryExpired(time.Now().Add(-2*time.Hour), time.Hour) { t.Fatalf("expected entry to be expired") } if isCacheEntryExpired(time.Now().Add(-30*time.Minute), time.Hour) { t.Fatalf("expected entry to be unexpired") } } func TestIsTrackedAsNoLyricsHonorsTTLAndPrunes(t *testing.T) { cache := &NoLyricsCache{Tracks: map[string]time.Time{ "old-track": time.Now().Add(-2 * time.Hour), "recent-track": time.Now().Add(-5 * time.Minute), }} if cache.IsTrackedAsNoLyrics("old-track", time.Hour) { t.Fatalf("expected old track to be treated as expired") } if _, exists := cache.Tracks["old-track"]; exists { t.Fatalf("expected expired track to be pruned") } if !cache.IsTrackedAsNoLyrics("recent-track", time.Hour) { t.Fatalf("expected recent track to remain cached") } } func TestParseRetryAfter(t *testing.T) { if got := parseRetryAfter("7"); got != 7*time.Second { t.Fatalf("expected 7s, got %s", got) } future := time.Now().Add(3 * time.Second).UTC().Format(time.RFC1123) got := parseRetryAfter(future) if got <= 0 || got > 3*time.Second { t.Fatalf("expected duration in (0s, 3s], got %s", got) } } func TestWriteFileAtomically(t *testing.T) { dir := t.TempDir() target := filepath.Join(dir, "cache.json") content := []byte("{\"track\":\"value\"}") if err := writeFileAtomically(target, content, 0644); err != nil { t.Fatalf("writeFileAtomically failed: %v", err) } got, err := os.ReadFile(target) if err != nil { t.Fatalf("failed to read target file: %v", err) } if string(got) != string(content) { t.Fatalf("unexpected content: %q", string(got)) } }