cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm leaflet readability golang
at main 273 lines 8.1 kB view raw
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}