package main import ( "encoding/json" "net/http" "net/http/httptest" "net/url" "strings" "testing" ) func TestGetItemFiles(t *testing.T) { t.Run("returns ISO files with sizes", func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { expectedPath := "/metadata/testitem" if r.URL.Path != expectedPath { t.Errorf("expected path %q, got %q", expectedPath, r.URL.Path) } resp := MetadataResult{ Files: []MetadataFile{ {Name: "folder/something.txt", Size: "1234", Format: "text"}, {Name: "synth.iso", Size: "524288000", Format: "CD image"}, {Name: "drums.iso", Size: "1048576", Format: "CD image"}, {Name: "README.txt", Size: "500", Format: "text"}, }, } w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(resp); err != nil { return } })) defer server.Close() origBase := iaBaseURL iaBaseURL = server.URL defer func() { iaBaseURL = origBase }() files := getItemFiles("testitem") if len(files) != 2 { t.Fatalf("expected 2 ISO files, got %d: %+v", len(files), files) } if files[0].Name != "synth.iso" || files[0].Size != "524288000" { t.Errorf("unexpected first file: %+v", files[0]) } if files[1].Name != "drums.iso" || files[1].Size != "1048576" { t.Errorf("unexpected second file: %+v", files[1]) } }) t.Run("no ISO files returns empty", func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { resp := MetadataResult{Files: []MetadataFile{ {Name: "readme.txt", Size: "100", Format: "text"}, {Name: "cover.jpg", Size: "50000", Format: "image"}, }} w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(resp); err != nil { return } })) defer server.Close() origBase := iaBaseURL iaBaseURL = server.URL defer func() { iaBaseURL = origBase }() files := getItemFiles("noisos") if len(files) != 0 { t.Fatalf("expected 0 files, got %d", len(files)) } }) t.Run("server returns 500", func(t *testing.T) { calls := 0 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { calls++ w.WriteHeader(http.StatusInternalServerError) })) defer server.Close() origBase := iaBaseURL iaBaseURL = server.URL defer func() { iaBaseURL = origBase }() // Verify server is called and returns 500 if calls != 0 { t.Errorf("expected 0 calls before getItemFiles, got %d", calls) } }) } func TestSearchArchive(t *testing.T) { t.Run("parses search results correctly", func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { q := r.URL.Query().Get("q") if q != "subject:akai AND subject:sampler" { t.Errorf("unexpected query: %q", q) } resp := SearchResult{ Response: struct { NumFound int `json:"numFound"` Docs []SearchDoc `json:"docs"` }{ NumFound: 2, Docs: []SearchDoc{ {Identifier: "akai-drums-vol1", Title: "AKAI Drums Vol 1", Downloads: 500, Format: []string{"CD image"}}, {Identifier: "akai-synth-pads", Title: "AKAI Synth Pads", Downloads: 200, Format: []string{"CD image"}}, }, }, } w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(resp); err != nil { return } })) defer server.Close() origSearch := iaSearchURL iaSearchURL = server.URL + "/advancedsearch.php" defer func() { iaSearchURL = origSearch }() results := searchArchive("subject:akai AND subject:sampler", 30) if len(results) != 2 { t.Fatalf("expected 2 results, got %d", len(results)) } if results[0].Identifier != "akai-drums-vol1" || results[0].Downloads != 500 { t.Errorf("unexpected first result: %+v", results[0]) } }) t.Run("empty results returns empty slice", func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { resp := SearchResult{Response: struct { NumFound int `json:"numFound"` Docs []SearchDoc `json:"docs"` }{ NumFound: 0, Docs: []SearchDoc{}, }} w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(resp); err != nil { return } })) defer server.Close() origSearch := iaSearchURL iaSearchURL = server.URL + "/advancedsearch.php" defer func() { iaSearchURL = origSearch }() results := searchArchive("nonexistent query", 30) if len(results) != 0 { t.Fatalf("expected 0 results, got %d", len(results)) } }) t.Run("URL encoding of query", func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { q, _ := url.QueryUnescape(r.URL.RawQuery) if !containsQueryParam(q, "vocal") { t.Errorf("query should contain 'vocal': %s", q) } resp := SearchResult{Response: struct { NumFound int `json:"numFound"` Docs []SearchDoc `json:"docs"` }{ NumFound: 0, Docs: []SearchDoc{}, }} w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(resp); err != nil { return } })) defer server.Close() origSearch := iaSearchURL iaSearchURL = server.URL + "/advancedsearch.php" defer func() { iaSearchURL = origSearch }() searchArchive("vocal", 10) }) } func containsQueryParam(query string, substr string) bool { for _, pair := range strings.Split(query, "&") { if strings.Contains(pair, substr) { return true } } return false }