package main import ( "context" "fmt" "os" "time" "musiclink/internal/detector" "musiclink/internal/resolver" "musiclink/internal/services" ) func main() { fmt.Println("=== MusicLink Smoke Test ===") // Test 1: Detector fmt.Println("1. Testing link detection...") testDetector() // Test 2: idonthavespotify API fmt.Println("\n2. Testing idonthavespotify API...") testAPI() // Test 3: Full resolution fmt.Println("\n3. Testing full resolution flow...") testResolver() fmt.Println("\n=== All tests passed! ===") } func testDetector() { det := detector.New() testCases := []struct { input string expected int }{ {"Check this out: https://open.spotify.com/track/4iV5W9uYEdYUVa79Axb7Rh", 1}, {"https://www.youtube.com/watch?v=dQw4w9WgXcQ", 1}, {"https://music.apple.com/us/album/some-album/123456789", 1}, {"https://www.deezer.com/track/123456", 1}, {"https://tidal.com/browse/track/12345678", 1}, {"No links here", 0}, {"Multiple: https://open.spotify.com/track/abc123 and https://youtu.be/dQw4w9WgXcQ", 2}, } for _, tc := range testCases { links := det.Detect(tc.input) if len(links) != tc.expected { fmt.Printf(" FAIL: Expected %d links, got %d for: %s\n", tc.expected, len(links), tc.input[:min(50, len(tc.input))]) os.Exit(1) } fmt.Printf(" OK: Found %d link(s) in: %s...\n", len(links), tc.input[:min(40, len(tc.input))]) } } func testAPI() { client := services.NewClient("") ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() // Test with a known Spotify track testURL := "https://open.spotify.com/track/4iV5W9uYEdYUVa79Axb7Rh" fmt.Printf(" Calling API with: %s\n", testURL) resp, err := resolveWithRetry(ctx, client, testURL) if err != nil { fmt.Printf(" FAIL: API error: %v\n", err) os.Exit(1) } fmt.Printf(" OK: Got response - Type: %s, Title: %s\n", resp.Type, resp.Title) fmt.Printf(" OK: Found %d platform links\n", len(resp.Links)) for _, link := range resp.Links { verified := "" if link.IsVerified { verified = " (verified)" } fmt.Printf(" - %s: %s%s\n", link.Type, link.URL[:min(50, len(link.URL))], verified) } } func testResolver() { res := resolver.New("") ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() testURL := "https://open.spotify.com/track/4iV5W9uYEdYUVa79Axb7Rh" fmt.Printf(" Resolving: %s\n", testURL) resolved, err := resolveResolverWithRetry(ctx, res, testURL) if err != nil { fmt.Printf(" FAIL: Resolver error: %v\n", err) os.Exit(1) } fmt.Printf(" OK: Resolved to %d platforms\n", len(resolved.Links)) // Test formatting title := "" if resolved.Track != nil { title = resolved.Track.Title } formatted := resolver.Format(resolved, title) fmt.Printf("\n Formatted output:\n") fmt.Println(" ---") for _, line := range splitLines(formatted) { fmt.Printf(" %s\n", line) } fmt.Println(" ---") } func min(a, b int) int { if a < b { return a } return b } func splitLines(s string) []string { var lines []string start := 0 for i, c := range s { if c == '\n' { lines = append(lines, s[start:i]) start = i + 1 } } if start < len(s) { lines = append(lines, s[start:]) } return lines } func resolveWithRetry(ctx context.Context, client *services.Client, url string) (*services.APIResponse, error) { const maxAttempts = 3 backoff := time.Second var lastErr error for attempt := 1; attempt <= maxAttempts; attempt++ { resp, err := client.Resolve(ctx, url) if err == nil { return resp, nil } lastErr = err if attempt == maxAttempts { break } if !sleepWithContext(ctx, backoff) { return nil, ctx.Err() } backoff *= 2 } return nil, lastErr } func resolveResolverWithRetry(ctx context.Context, res *resolver.Resolver, url string) (*services.ResolvedLinks, error) { const maxAttempts = 3 backoff := time.Second var lastErr error for attempt := 1; attempt <= maxAttempts; attempt++ { resp, err := res.Resolve(ctx, url) if err == nil { return resp, nil } lastErr = err if attempt == maxAttempts { break } if !sleepWithContext(ctx, backoff) { return nil, ctx.Err() } backoff *= 2 } return nil, lastErr } func sleepWithContext(ctx context.Context, delay time.Duration) bool { timer := time.NewTimer(delay) defer timer.Stop() select { case <-ctx.Done(): return false case <-timer.C: return true } }