cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm
leaflet
readability
golang
1package services
2
3import (
4 "bytes"
5 "context"
6 "strings"
7 "testing"
8
9 "github.com/stormlightlabs/noteleaf/internal/models"
10)
11
12func TestMediaServices(t *testing.T) {
13 t.Run("MovieService", func(t *testing.T) {
14 t.Run("Search", func(t *testing.T) {
15 t.Run("successful search", func(t *testing.T) {
16 cleanup := SetupSuccessfulMovieMocks(t)
17 defer cleanup()
18
19 service := CreateMovieService()
20 TestMovieSearch(t, service, "Fantastic Four", "Fantastic Four")
21 })
22
23 t.Run("search returns error", func(t *testing.T) {
24 cleanup := SetupFailureMocks(t, "search error")
25 defer cleanup()
26
27 service := CreateMovieService()
28 _, err := service.Search(context.Background(), "error", 1, 10)
29 AssertErrorContains(t, err, "search error")
30 })
31 })
32
33 t.Run("Get", func(t *testing.T) {
34 t.Run("successful get", func(t *testing.T) {
35 cleanup := SetupSuccessfulMovieMocks(t)
36 defer cleanup()
37
38 service := CreateMovieService()
39 result, err := service.Get(context.Background(), "some-url")
40 if err != nil {
41 t.Fatalf("Get failed: %v", err)
42 }
43 movie, ok := (*result).(*models.Movie)
44 if !ok {
45 t.Fatalf("expected a movie model, got %T", *result)
46 }
47 if movie.Title == "" {
48 t.Error("expected non-empty movie title")
49 }
50 })
51
52 t.Run("get returns error", func(t *testing.T) {
53 cleanup := SetupFailureMocks(t, "fetch error")
54 defer cleanup()
55
56 service := CreateMovieService()
57 _, err := service.Get(context.Background(), "error")
58 AssertErrorContains(t, err, "fetch error")
59 })
60 })
61
62 t.Run("Check", func(t *testing.T) {
63 t.Run("successful check", func(t *testing.T) {
64 cleanup := SetupSuccessfulMovieMocks(t)
65 defer cleanup()
66
67 service := CreateMovieService()
68 err := service.Check(context.Background())
69 if err != nil {
70 t.Fatalf("Check failed: %v", err)
71 }
72 })
73
74 t.Run("check returns error", func(t *testing.T) {
75 cleanup := SetupFailureMocks(t, "html fetch error")
76 defer cleanup()
77
78 service := CreateMovieService()
79 err := service.Check(context.Background())
80 AssertErrorContains(t, err, "html fetch error")
81 })
82 })
83
84 t.Run("Parse Search results", func(t *testing.T) {
85 results, err := ParseSearch(bytes.NewReader(SearchSample))
86 if err != nil {
87 t.Fatalf("ParseSearch failed: %v", err)
88 }
89 if len(results) == 0 {
90 t.Fatal("expected non-empty search results")
91 }
92 })
93
94 t.Run("Parse Search error", func(t *testing.T) {
95 results, err := ParseSearch(strings.NewReader("\x00bad html"))
96 if err != nil {
97 t.Fatalf("unexpected error for malformed HTML: %v", err)
98 }
99 if len(results) != 0 {
100 t.Errorf("expected 0 results for malformed HTML, got %d", len(results))
101 }
102
103 html := `<a class="score-list-item"><span>Test</span></a>`
104 results, err = ParseSearch(strings.NewReader(html))
105 if err != nil {
106 t.Fatalf("unexpected error: %v", err)
107 }
108 if len(results) != 0 {
109 t.Errorf("expected 0 results, got %d", len(results))
110 }
111 })
112
113 t.Run("Extract Metadata", func(t *testing.T) {
114 movie, err := ExtractMovieMetadata(bytes.NewReader(MovieSample))
115 if err != nil {
116 t.Fatalf("ExtractMovieMetadata failed: %v", err)
117 }
118 if movie.Type != "Movie" {
119 t.Errorf("expected Type=Movie, got %s", movie.Type)
120 }
121 if movie.Name == "" {
122 t.Error("expected non-empty Name")
123 }
124 })
125
126 t.Run("Extract Metadata Errors", func(t *testing.T) {
127 if _, err := ExtractMovieMetadata(strings.NewReader("not html")); err == nil {
128 t.Error("expected error for invalid HTML")
129 }
130
131 html := `<script type="application/ld+json">{"@type":"Other"}</script>`
132 if _, err := ExtractMovieMetadata(strings.NewReader(html)); err == nil || !strings.Contains(err.Error(), "no Movie JSON-LD") {
133 t.Errorf("expected 'no Movie JSON-LD', got %v", err)
134 }
135
136 html = `<script type="application/ld+json">{oops}</script>`
137 if _, err := ExtractMovieMetadata(strings.NewReader(html)); err == nil {
138 t.Error("expected error for invalid JSON")
139 }
140 })
141
142 t.Run("Extract TV Series Metadata", func(t *testing.T) {
143 series, err := ExtractTVSeriesMetadata(bytes.NewReader(SeriesSample))
144 if err != nil {
145 t.Fatalf("ExtractTVSeriesMetadata failed: %v", err)
146 }
147 if series.Type != "TVSeries" {
148 t.Errorf("expected Type=TVSeries, got %s", series.Type)
149 }
150 if series.NumberOfSeasons <= 0 {
151 t.Error("expected NumberOfSeasons > 0")
152 }
153 })
154
155 t.Run("Extract TV Series Metadata Errors", func(t *testing.T) {
156 if _, err := ExtractTVSeriesMetadata(strings.NewReader("not html")); err == nil {
157 t.Error("expected error for invalid HTML")
158 }
159
160 html := `<script type="application/ld+json">{"@type":"Other"}</script>`
161 if _, err := ExtractTVSeriesMetadata(strings.NewReader(html)); err == nil || !strings.Contains(err.Error(), "no TVSeries JSON-LD") {
162 t.Errorf("expected 'no TVSeries JSON-LD', got %v", err)
163 }
164 })
165
166 t.Run("Extract TV Series Season metadata", func(t *testing.T) {
167 season, err := ExtractTVSeasonMetadata(bytes.NewReader(SeasonSample))
168 if err != nil {
169 t.Fatalf("ExtractTVSeasonMetadata failed: %v", err)
170 }
171 if season.Type != "TVSeason" {
172 t.Errorf("expected Type=TVSeason, got %s", season.Type)
173 }
174 if season.SeasonNumber <= 0 {
175 t.Error("expected SeasonNumber > 0")
176 }
177 if season.PartOfSeries.Name == "" {
178 t.Error("expected non-empty PartOfSeries.Name")
179 }
180 })
181
182 t.Run("Extract TV Series Season errors", func(t *testing.T) {
183 if _, err := ExtractTVSeasonMetadata(strings.NewReader("not html")); err == nil {
184 t.Error("expected error for invalid HTML")
185 }
186
187 html := `<script type="application/ld+json">{"@type":"Other"}</script>`
188 if _, err := ExtractTVSeasonMetadata(strings.NewReader(html)); err == nil || !strings.Contains(err.Error(), "no TVSeason JSON-LD") {
189 t.Errorf("expected 'no TVSeason JSON-LD', got %v", err)
190 }
191 })
192
193 t.Run("Fetch HTML errors", func(t *testing.T) {
194 if _, err := FetchHTML("://bad-url"); err == nil {
195 t.Error("expected error for invalid URL")
196 }
197 })
198
199 })
200
201 t.Run("TVService", func(t *testing.T) {
202 t.Run("Search", func(t *testing.T) {
203 t.Run("successful search", func(t *testing.T) {
204 cleanup := SetupSuccessfulTVMocks(t)
205 defer cleanup()
206
207 service := CreateTVService()
208 TestTVSearch(t, service, "peacemaker", "Peacemaker")
209 })
210
211 t.Run("search returns error", func(t *testing.T) {
212 cleanup := SetupFailureMocks(t, "search error")
213 defer cleanup()
214
215 service := CreateTVService()
216 _, err := service.Search(context.Background(), "error", 1, 10)
217 AssertErrorContains(t, err, "search error")
218 })
219 })
220
221 t.Run("Get", func(t *testing.T) {
222 t.Run("successful get", func(t *testing.T) {
223 cleanup := SetupSuccessfulTVMocks(t)
224 defer cleanup()
225
226 service := CreateTVService()
227 result, err := service.Get(context.Background(), "some-url")
228 if err != nil {
229 t.Fatalf("Get failed: %v", err)
230 }
231 show, ok := (*result).(*models.TVShow)
232 if !ok {
233 t.Fatalf("expected a tv show model, got %T", *result)
234 }
235 if show.Title == "" {
236 t.Error("expected non-empty TV show title")
237 }
238 })
239
240 t.Run("get returns error", func(t *testing.T) {
241 cleanup := SetupFailureMocks(t, "fetch error")
242 defer cleanup()
243
244 service := CreateTVService()
245 _, err := service.Get(context.Background(), "error")
246 AssertErrorContains(t, err, "fetch error")
247 })
248 })
249
250 t.Run("Check", func(t *testing.T) {
251 t.Run("successful check", func(t *testing.T) {
252 cleanup := SetupSuccessfulTVMocks(t)
253 defer cleanup()
254
255 service := CreateTVService()
256 err := service.Check(context.Background())
257 if err != nil {
258 t.Fatalf("Check failed: %v", err)
259 }
260 })
261
262 t.Run("check returns error", func(t *testing.T) {
263 cleanup := SetupFailureMocks(t, "html fetch error")
264 defer cleanup()
265
266 service := CreateTVService()
267 err := service.Check(context.Background())
268 AssertErrorContains(t, err, "html fetch error")
269 })
270 })
271 })
272}