/
ctrl_test.go
118 lines (101 loc) · 2.98 KB
/
ctrl_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package ctrlsubsonic
import (
"context"
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path"
"regexp"
"strings"
"testing"
jd "github.com/josephburnett/jd/lib"
"go.senan.xyz/gonic/server/ctrlbase"
"go.senan.xyz/gonic/server/ctrlsubsonic/params"
"go.senan.xyz/gonic/server/mockfs"
)
var (
testDataDir = "testdata"
testCamelExpr = regexp.MustCompile("([a-z0-9])([A-Z])")
)
type queryCase struct {
params url.Values
expectPath string
listSet bool
}
func makeGoldenPath(test string) string {
// convert test name to query case path
snake := testCamelExpr.ReplaceAllString(test, "${1}_${2}")
lower := strings.ToLower(snake)
relPath := strings.ReplaceAll(lower, "/", "_")
return path.Join(testDataDir, relPath)
}
func makeHTTPMock(query url.Values) (*httptest.ResponseRecorder, *http.Request) {
// ensure the handlers give us json
query.Add("f", "json")
// request from the handler in question
req, _ := http.NewRequest("", "", nil)
req.URL.RawQuery = query.Encode()
subParams := params.New(req)
withParams := context.WithValue(req.Context(), CtxParams, subParams)
rr := httptest.NewRecorder()
req = req.WithContext(withParams)
return rr, req
}
func runQueryCases(t *testing.T, contr *Controller, h handlerSubsonic, cases []*queryCase) {
t.Helper()
for _, qc := range cases {
t.Run(qc.expectPath, func(t *testing.T) {
rr, req := makeHTTPMock(qc.params)
contr.H(h).ServeHTTP(rr, req)
body := rr.Body.String()
if status := rr.Code; status != http.StatusOK {
t.Fatalf("didn't give a 200\n%s", body)
}
goldenPath := makeGoldenPath(t.Name())
goldenRegen := os.Getenv("GONIC_REGEN")
if goldenRegen == "*" || (goldenRegen != "" && strings.HasPrefix(t.Name(), goldenRegen)) {
_ = os.WriteFile(goldenPath, []byte(body), 0600)
t.Logf("golden file %q regenerated for %s", goldenPath, t.Name())
t.SkipNow()
}
// read case to differ with handler result
expected, err := jd.ReadJsonFile(goldenPath)
if err != nil {
t.Fatalf("parsing expected: %v", err)
}
actual, err := jd.ReadJsonString(body)
if err != nil {
t.Fatalf("parsing actual: %v", err)
}
diffOpts := []jd.Metadata{}
if qc.listSet {
diffOpts = append(diffOpts, jd.SET)
}
diff := expected.Diff(actual, diffOpts...)
if len(diff) > 0 {
t.Errorf("\u001b[31;1mdiffering json\u001b[0m\n%s", diff.Render())
}
})
}
}
func makeController(t *testing.T) (*Controller, *mockfs.MockFS) { return makec(t, []string{""}) }
func makeControllerRoots(t *testing.T, r []string) (*Controller, *mockfs.MockFS) { return makec(t, r) }
func makec(t *testing.T, roots []string) (*Controller, *mockfs.MockFS) {
t.Helper()
m := mockfs.NewWithDirs(t, roots)
for _, root := range roots {
m.AddItemsPrefixWithCovers(root)
}
m.ScanAndClean()
m.ResetDates()
m.LogAlbums()
base := &ctrlbase.Controller{DB: m.DB()}
return &Controller{Controller: base}, m
}
func TestMain(m *testing.M) {
log.SetOutput(ioutil.Discard)
os.Exit(m.Run())
}