120993fb02
- cli_test.go: 10 tests for list/search/extract/download commands - serve_test.go: 11 tests for HTTP handlers and SSE progress - http_test.go: 5 subtests for archive.org API - download_test.go: 10 tests for download logic - util_test.go: 7 tests for string/util helpers Error paths covered: server errors, empty results, download failures, extract failures, missing identifiers, ReadDir errors. golangci-lint: 0 issues, go vet: clean
191 lines
5.5 KiB
Go
191 lines
5.5 KiB
Go
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
|
|
} |