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