mirror of
https://github.com/5rahim/seanime
synced 2026-04-25 22:34:56 +02:00
refactored tests
This commit is contained in:
@@ -188,24 +188,45 @@ go mod tidy
|
||||
|
||||
#### Writing Tests
|
||||
|
||||
Tests use the `test_utils` package which provides:
|
||||
- `InitTestProvider` method to initialize the test configuration
|
||||
- Flags to enable/disable specific test categories
|
||||
Tests use the `internal/testutil` package which provides:
|
||||
|
||||
- `InitTestProvider` to load test configuration and apply feature-flag skips
|
||||
- `NewTestEnv` to create an isolated temp root, app data dir, cache dir, and database for tests
|
||||
- `FixtureRelPath` and fixture helpers
|
||||
- `RequireSampleVideoPath` for media-player tests that need a real sample file
|
||||
|
||||
Example:
|
||||
```go
|
||||
func TestSomething(t *testing.T) {
|
||||
test_utils.InitTestProvider(t, test_utils.Anilist())
|
||||
// Test code here
|
||||
env := testutil.NewTestEnv(t, testutil.Anilist())
|
||||
database := env.MustNewDatabase(util.NewLogger())
|
||||
_ = database
|
||||
}
|
||||
```
|
||||
|
||||
AniList mock fixtures are read-only during normal test runs. Set `SEANIME_TEST_RECORD_ANILIST_FIXTURES=true` when you intentionally want missing or refreshed fixtures written back to the repository.
|
||||
|
||||
To avoid remembering the environment variable and basic auth checks, use the refresh wrapper:
|
||||
|
||||
```bash
|
||||
go run ./scripts/record_anilist_fixtures
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- It validates that `test/config.toml` exists, `flags.enable_anilist_tests=true`, and `provider.anilist_jwt` is set.
|
||||
- It defaults to refreshing `./internal/api/anilist` and sets `SEANIME_TEST_RECORD_ANILIST_FIXTURES=true` for the test process.
|
||||
- Pass packages to widen the refresh scope, for example `go run ./scripts/record_anilist_fixtures ./internal/api/anilist ./internal/library/scanner`.
|
||||
- Pass `-run` to target specific live refresh tests, for example `go run ./scripts/record_anilist_fixtures -run 'TestGetAnimeByIdLive|TestBaseAnime_FetchMediaTree_BaseAnimeLive'`.
|
||||
|
||||
#### Testing with Third-Party Apps
|
||||
|
||||
Some tests interact with applications like Transmission and qBittorrent:
|
||||
- Ensure these applications are installed and running
|
||||
- Configure `test/config.toml` with appropriate connection details
|
||||
|
||||
Media-player tests that open a file also require `path.sampleVideoPath` in `test/config.toml`, or `TEST_SAMPLE_VIDEO_PATH` in the environment.
|
||||
|
||||
## Notes and Warnings
|
||||
|
||||
- hls.js versions 1.6.0 and above may cause appendBuffer fatal errors
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,71 +3,93 @@ package anilist
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"seanime/internal/testutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// USE CASE: Generate a boilerplate Anilist AnimeCollection for testing purposes and save it to 'test/data/BoilerplateAnimeCollection'.
|
||||
// The generated AnimeCollection will have all entries in the 'Planning' status.
|
||||
// The generated AnimeCollection will be used to test various Anilist API methods.
|
||||
// You can use TestModifyAnimeCollectionEntry to modify the generated AnimeCollection before using it in a test.
|
||||
// - DO NOT RUN IF YOU DON'T PLAN TO GENERATE A NEW 'test/data/BoilerplateAnimeCollection'
|
||||
func TestGenerateBoilerplateAnimeCollection(t *testing.T) {
|
||||
t.Skip("This test is not meant to be run")
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
const recordCompleteAnimeIDsEnvName = "SEANIME_TEST_RECORD_COMPLETE_ANIME_IDS"
|
||||
|
||||
anilistClient := TestGetMockAnilistClient()
|
||||
func TestMaybeWriteJSONFixtureCreatesDirectories(t *testing.T) {
|
||||
t.Setenv(testutil.RecordAnilistFixturesEnvName, "true")
|
||||
|
||||
ac, err := anilistClient.AnimeCollection(context.Background(), &cfg.Provider.AnilistUsername)
|
||||
target := filepath.Join(t.TempDir(), "fixtures", "nested", "fixture.json")
|
||||
err := maybeWriteJSONFixture(target, map[string]string{"status": "ok"}, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
|
||||
lists := ac.GetMediaListCollection().GetLists()
|
||||
|
||||
entriesToAddToPlanning := make([]*AnimeListEntry, 0)
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
|
||||
for _, list := range lists {
|
||||
if list.Status != nil {
|
||||
if list.GetStatus().String() != string(MediaListStatusPlanning) {
|
||||
entries := list.GetEntries()
|
||||
for _, entry := range entries {
|
||||
entry.Progress = new(0)
|
||||
entry.Score = new(0.0)
|
||||
entry.Status = new(MediaListStatusPlanning)
|
||||
entriesToAddToPlanning = append(entriesToAddToPlanning, entry)
|
||||
}
|
||||
list.Entries = make([]*AnimeListEntry, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newLists := make([]*AnimeCollection_MediaListCollection_Lists, 0)
|
||||
for _, list := range lists {
|
||||
if list.Status == nil {
|
||||
continue
|
||||
}
|
||||
if *list.GetStatus() == MediaListStatusPlanning {
|
||||
list.Entries = append(list.Entries, entriesToAddToPlanning...)
|
||||
newLists = append(newLists, list)
|
||||
} else {
|
||||
newLists = append(newLists, list)
|
||||
}
|
||||
}
|
||||
|
||||
ac.MediaListCollection.Lists = newLists
|
||||
|
||||
data, err := json.Marshal(ac)
|
||||
if assert.NoError(t, err) {
|
||||
err = os.WriteFile(testutil.DataPath("BoilerplateAnimeCollection"), data, 0644)
|
||||
_, err = os.Stat(target)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCustomQueryFixturePathIsStable(t *testing.T) {
|
||||
body := []byte(`{"query":"query Example { Page { pageInfo { total } } }","variables":{"page":1}}`)
|
||||
|
||||
path1 := customQueryFixturePath(body)
|
||||
path2 := customQueryFixturePath(body)
|
||||
|
||||
assert.Equal(t, path1, path2)
|
||||
assert.Contains(t, path1, filepath.Join("test", "testdata", "anilist-custom-query"))
|
||||
}
|
||||
|
||||
func TestFixtureMangaCollectionUsesCommittedFixture(t *testing.T) {
|
||||
client := NewFixtureAnilistClient()
|
||||
|
||||
collection, err := client.MangaCollection(context.Background(), nil)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, collection)
|
||||
|
||||
entry, found := collection.GetListEntryFromMangaId(101517)
|
||||
require.True(t, found)
|
||||
require.Equal(t, MediaListStatusCurrent, *entry.GetStatus())
|
||||
require.Equal(t, 260, *entry.GetProgress())
|
||||
}
|
||||
|
||||
func TestRecordCompleteAnimeByIDFixtures(t *testing.T) {
|
||||
if !testutil.ShouldRecordAnilistFixtures() {
|
||||
t.Skip("AniList fixture recording disabled")
|
||||
}
|
||||
|
||||
rawIDs := strings.TrimSpace(os.Getenv(recordCompleteAnimeIDsEnvName))
|
||||
if rawIDs == "" {
|
||||
t.Skip("no CompleteAnimeByID fixture ids requested")
|
||||
}
|
||||
|
||||
cfg := testutil.LoadConfig(t)
|
||||
if cfg.Provider.AnilistJwt == "" {
|
||||
t.Skip("AniList fixture recording requires provider.anilist_jwt")
|
||||
}
|
||||
|
||||
client := NewFixtureAnilistClientWithToken(cfg.Provider.AnilistJwt)
|
||||
for _, mediaID := range parseFixtureMediaIDs(t, rawIDs) {
|
||||
_, err := client.CompleteAnimeByID(context.Background(), &mediaID)
|
||||
require.NoErrorf(t, err, "failed to record CompleteAnimeByID fixture for media %d", mediaID)
|
||||
}
|
||||
}
|
||||
|
||||
func parseFixtureMediaIDs(t *testing.T, raw string) []int {
|
||||
t.Helper()
|
||||
|
||||
parts := strings.FieldsFunc(raw, func(r rune) bool {
|
||||
switch r {
|
||||
case ',', ' ', '\n', '\t':
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
})
|
||||
require.NotEmpty(t, parts, "expected at least one media id")
|
||||
|
||||
ids := make([]int, 0, len(parts))
|
||||
for _, part := range parts {
|
||||
mediaID, err := strconv.Atoi(part)
|
||||
require.NoErrorf(t, err, "invalid media id %q", part)
|
||||
ids = append(ids, mediaID)
|
||||
}
|
||||
|
||||
return ids
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package anilist
|
||||
|
||||
import (
|
||||
"context"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/util"
|
||||
"testing"
|
||||
|
||||
@@ -10,145 +9,16 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
//func TestHiddenFromStatus(t *testing.T) {
|
||||
// test_utils.InitTestProvider(t, test_utils.Anilist())
|
||||
//
|
||||
// cfg := test_utils.InitTestProvider(t, test_utils.Anilist())
|
||||
// token := cfg.Provider.AnilistJwt
|
||||
// logger := util.NewLogger()
|
||||
// //anilistClient := NewAnilistClient(cfg.Provider.AnilistJwt)
|
||||
//
|
||||
// variables := map[string]interface{}{}
|
||||
//
|
||||
// variables["userName"] = cfg.Provider.AnilistUsername
|
||||
// variables["type"] = "ANIME"
|
||||
//
|
||||
// requestBody, err := json.Marshal(map[string]interface{}{
|
||||
// "query": testQuery,
|
||||
// "variables": variables,
|
||||
// })
|
||||
// require.NoError(t, err)
|
||||
//
|
||||
// data, err := customQuery(requestBody, logger, token)
|
||||
// require.NoError(t, err)
|
||||
//
|
||||
// var mediaLists []*MediaList
|
||||
//
|
||||
// type retData struct {
|
||||
// Page Page
|
||||
// PageInfo PageInfo
|
||||
// }
|
||||
//
|
||||
// var ret retData
|
||||
// m, err := json.Marshal(data)
|
||||
// require.NoError(t, err)
|
||||
// if err := json.Unmarshal(m, &ret); err != nil {
|
||||
// t.Fatalf("Failed to unmarshal data: %v", err)
|
||||
// }
|
||||
//
|
||||
// mediaLists = append(mediaLists, ret.Page.MediaList...)
|
||||
//
|
||||
// util.Spew(ret.Page.PageInfo)
|
||||
//
|
||||
// var currentPage = 1
|
||||
// var hasNextPage = false
|
||||
// if ret.Page.PageInfo != nil && ret.Page.PageInfo.HasNextPage != nil {
|
||||
// hasNextPage = *ret.Page.PageInfo.HasNextPage
|
||||
// }
|
||||
// for hasNextPage {
|
||||
// currentPage++
|
||||
// variables["page"] = currentPage
|
||||
// requestBody, err = json.Marshal(map[string]interface{}{
|
||||
// "query": testQuery,
|
||||
// "variables": variables,
|
||||
// })
|
||||
// require.NoError(t, err)
|
||||
// data, err = customQuery(requestBody, logger, token)
|
||||
// require.NoError(t, err)
|
||||
// m, err = json.Marshal(data)
|
||||
// require.NoError(t, err)
|
||||
// if err := json.Unmarshal(m, &ret); err != nil {
|
||||
// t.Fatalf("Failed to unmarshal data: %v", err)
|
||||
// }
|
||||
// util.Spew(ret.Page.PageInfo)
|
||||
// if ret.Page.PageInfo != nil && ret.Page.PageInfo.HasNextPage != nil {
|
||||
// hasNextPage = *ret.Page.PageInfo.HasNextPage
|
||||
// }
|
||||
// mediaLists = append(mediaLists, ret.Page.MediaList...)
|
||||
// }
|
||||
//
|
||||
// //res, err := anilistClient.AnimeCollection(context.Background(), &cfg.Provider.AnilistUsername)
|
||||
// //assert.NoError(t, err)
|
||||
//
|
||||
// for _, mediaList := range mediaLists {
|
||||
// util.Spew(mediaList.Media.ID)
|
||||
// if mediaList.Media.ID == 151514 {
|
||||
// util.Spew(mediaList)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
//
|
||||
//const testQuery = `query ($page: Int, $userName: String, $type: MediaType) {
|
||||
// Page (page: $page, perPage: 100) {
|
||||
// pageInfo {
|
||||
// hasNextPage
|
||||
// total
|
||||
// perPage
|
||||
// currentPage
|
||||
// lastPage
|
||||
// }
|
||||
// mediaList (type: $type, userName: $userName) {
|
||||
// status
|
||||
// startedAt {
|
||||
// year
|
||||
// month
|
||||
// day
|
||||
// }
|
||||
// completedAt {
|
||||
// year
|
||||
// month
|
||||
// day
|
||||
// }
|
||||
// repeat
|
||||
// score(format: POINT_100)
|
||||
// progress
|
||||
// progressVolumes
|
||||
// notes
|
||||
// media {
|
||||
// siteUrl
|
||||
// id
|
||||
// idMal
|
||||
// episodes
|
||||
// chapters
|
||||
// volumes
|
||||
// status
|
||||
// averageScore
|
||||
// coverImage{
|
||||
// large
|
||||
// extraLarge
|
||||
// }
|
||||
// bannerImage
|
||||
// title {
|
||||
// userPreferred
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }`
|
||||
|
||||
func TestGetAnimeById(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := TestGetMockAnilistClient()
|
||||
anilistClient := NewTestAnilistClient()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
mediaId int
|
||||
}{
|
||||
{
|
||||
name: "Cowboy Bebop",
|
||||
mediaId: 1,
|
||||
name: "Re:Zero",
|
||||
mediaId: 21355,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -161,9 +31,16 @@ func TestGetAnimeById(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestListAnime(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
func TestGetAnimeByIdLive(t *testing.T) {
|
||||
anilistClient := newLiveAnilistClient(t)
|
||||
mediaID := 1
|
||||
|
||||
res, err := anilistClient.BaseAnimeByID(context.Background(), &mediaID)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, res)
|
||||
}
|
||||
|
||||
func TestListAnime(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
Page *int
|
||||
@@ -196,7 +73,7 @@ func TestListAnime(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
anilistClient := TestGetMockAnilistClient()
|
||||
anilistClient := NewTestAnilistClient()
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func TestCompoundQuery(t *testing.T) {
|
||||
testutil.InitTestProvider(t)
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
var ids = []int{171457, 21}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package anilist
|
||||
|
||||
import (
|
||||
"context"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/util/limiter"
|
||||
"testing"
|
||||
|
||||
@@ -11,9 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func TestBaseAnime_FetchMediaTree_BaseAnime(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := TestGetMockAnilistClient()
|
||||
anilistClient := NewTestAnilistClient()
|
||||
lim := limiter.NewAnilistLimiter()
|
||||
completeAnimeCache := NewCompleteAnimeCache()
|
||||
|
||||
@@ -33,16 +30,6 @@ func TestBaseAnime_FetchMediaTree_BaseAnime(t *testing.T) {
|
||||
163263, // BSD5
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Re:Zero",
|
||||
mediaId: 21355,
|
||||
edgeIds: []int{
|
||||
21355, // Re:Zero 1
|
||||
108632, // Re:Zero 2
|
||||
119661, // Re:Zero 2 Part 2
|
||||
163134, // Re:Zero 3
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -81,3 +68,36 @@ func TestBaseAnime_FetchMediaTree_BaseAnime(t *testing.T) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestBaseAnime_FetchMediaTree_BaseAnimeLive(t *testing.T) {
|
||||
anilistClient := newLiveAnilistClient(t)
|
||||
lim := limiter.NewAnilistLimiter()
|
||||
completeAnimeCache := NewCompleteAnimeCache()
|
||||
mediaID := 21355
|
||||
edgeIDs := []int{21355, 108632, 119661, 163134}
|
||||
|
||||
mediaF, err := anilistClient.CompleteAnimeByID(context.Background(), &mediaID)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
media := mediaF.GetMedia()
|
||||
tree := NewCompleteAnimeRelationTree()
|
||||
|
||||
err = media.FetchMediaTree(
|
||||
FetchMediaTreeAll,
|
||||
anilistClient,
|
||||
lim,
|
||||
tree,
|
||||
completeAnimeCache,
|
||||
)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
for _, treeID := range edgeIDs {
|
||||
a, found := tree.Get(treeID)
|
||||
assert.Truef(t, found, "expected tree to contain %d", treeID)
|
||||
spew.Dump(a.GetTitleSafe())
|
||||
}
|
||||
}
|
||||
|
||||
17
internal/api/anilist/test_client_helpers_test.go
Normal file
17
internal/api/anilist/test_client_helpers_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package anilist
|
||||
|
||||
import (
|
||||
"seanime/internal/testutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func newLiveAnilistClient(t testing.TB) AnilistClient {
|
||||
t.Helper()
|
||||
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
if cfg.Provider.AnilistJwt == "" {
|
||||
t.Skip("anilist live tests require anilist_jwt")
|
||||
}
|
||||
|
||||
return NewAnilistClient(cfg.Provider.AnilistJwt, "")
|
||||
}
|
||||
286
internal/api/anilist/test_collection_helpers.go
Normal file
286
internal/api/anilist/test_collection_helpers.go
Normal file
@@ -0,0 +1,286 @@
|
||||
package anilist
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type AnimeCollectionEntryPatch struct {
|
||||
Status *MediaListStatus
|
||||
Progress *int
|
||||
Score *float64
|
||||
Repeat *int
|
||||
AiredEpisodes *int
|
||||
NextAiringEpisode *BaseAnime_NextAiringEpisode
|
||||
}
|
||||
|
||||
func PatchAnimeCollectionEntry(collection *AnimeCollection, mediaID int, patch AnimeCollectionEntryPatch) *AnimeCollection {
|
||||
if collection == nil {
|
||||
panic("anilist: anime collection is nil")
|
||||
}
|
||||
|
||||
entry, currentList := findAnimeCollectionEntry(collection, mediaID)
|
||||
if entry == nil {
|
||||
panic(fmt.Sprintf("anilist: anime %d not found in collection; use EnsureAnimeCollectionEntry for missing media", mediaID))
|
||||
}
|
||||
|
||||
if patch.Status != nil {
|
||||
currentList = moveAnimeEntryToStatus(collection, currentList, entry, *patch.Status)
|
||||
_ = currentList
|
||||
}
|
||||
|
||||
applyAnimeCollectionEntryPatch(entry, patch)
|
||||
return collection
|
||||
}
|
||||
|
||||
func EnsureAnimeCollectionEntry(collection *AnimeCollection, mediaID int, patch AnimeCollectionEntryPatch, client AnilistClient) *AnimeCollection {
|
||||
if collection == nil {
|
||||
panic("anilist: anime collection is nil")
|
||||
}
|
||||
if _, currentList := findAnimeCollectionEntry(collection, mediaID); currentList != nil {
|
||||
return collection
|
||||
}
|
||||
if client == nil {
|
||||
panic(fmt.Sprintf("anilist: cannot add anime %d without a client", mediaID))
|
||||
}
|
||||
if patch.Status == nil {
|
||||
panic(fmt.Sprintf("anilist: cannot add anime %d without a status", mediaID))
|
||||
}
|
||||
|
||||
baseAnime, err := client.BaseAnimeByID(context.Background(), &mediaID)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
entry := &AnimeCollection_MediaListCollection_Lists_Entries{
|
||||
Media: baseAnime.GetMedia(),
|
||||
}
|
||||
list := ensureAnimeStatusList(collection, *patch.Status)
|
||||
list.Entries = append(list.Entries, entry)
|
||||
|
||||
return PatchAnimeCollectionEntry(collection, mediaID, patch)
|
||||
}
|
||||
|
||||
func PatchAnimeCollectionWithRelationsEntry(collection *AnimeCollectionWithRelations, mediaID int, patch AnimeCollectionEntryPatch) *AnimeCollectionWithRelations {
|
||||
if collection == nil {
|
||||
panic("anilist: anime collection with relations is nil")
|
||||
}
|
||||
|
||||
entry, currentList := findAnimeCollectionWithRelationsEntry(collection, mediaID)
|
||||
if entry == nil {
|
||||
panic(fmt.Sprintf("anilist: anime %d not found in relation collection; use EnsureAnimeCollectionWithRelationsEntry for missing media", mediaID))
|
||||
}
|
||||
|
||||
if patch.Status != nil {
|
||||
currentList = moveAnimeRelationsEntryToStatus(collection, currentList, entry, *patch.Status)
|
||||
_ = currentList
|
||||
}
|
||||
|
||||
applyAnimeCollectionWithRelationsEntryPatch(entry, patch)
|
||||
return collection
|
||||
}
|
||||
|
||||
func EnsureAnimeCollectionWithRelationsEntry(collection *AnimeCollectionWithRelations, mediaID int, patch AnimeCollectionEntryPatch, client AnilistClient) *AnimeCollectionWithRelations {
|
||||
if collection == nil {
|
||||
panic("anilist: anime collection with relations is nil")
|
||||
}
|
||||
if _, currentList := findAnimeCollectionWithRelationsEntry(collection, mediaID); currentList != nil {
|
||||
return collection
|
||||
}
|
||||
if client == nil {
|
||||
panic(fmt.Sprintf("anilist: cannot add anime %d without a client", mediaID))
|
||||
}
|
||||
if patch.Status == nil {
|
||||
panic(fmt.Sprintf("anilist: cannot add anime %d without a status", mediaID))
|
||||
}
|
||||
|
||||
completeAnime, err := client.CompleteAnimeByID(context.Background(), &mediaID)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
entry := &AnimeCollectionWithRelations_MediaListCollection_Lists_Entries{
|
||||
Media: completeAnime.GetMedia(),
|
||||
}
|
||||
list := ensureAnimeRelationsStatusList(collection, *patch.Status)
|
||||
list.Entries = append(list.Entries, entry)
|
||||
|
||||
return PatchAnimeCollectionWithRelationsEntry(collection, mediaID, patch)
|
||||
}
|
||||
|
||||
func applyAnimeCollectionEntryPatch(entry *AnimeCollection_MediaListCollection_Lists_Entries, patch AnimeCollectionEntryPatch) {
|
||||
if patch.Status != nil {
|
||||
entry.Status = patch.Status
|
||||
}
|
||||
if patch.Progress != nil {
|
||||
entry.Progress = patch.Progress
|
||||
}
|
||||
if patch.Score != nil {
|
||||
entry.Score = patch.Score
|
||||
}
|
||||
if patch.Repeat != nil {
|
||||
entry.Repeat = patch.Repeat
|
||||
}
|
||||
if patch.AiredEpisodes != nil {
|
||||
entry.Media.Episodes = patch.AiredEpisodes
|
||||
}
|
||||
if patch.NextAiringEpisode != nil {
|
||||
entry.Media.NextAiringEpisode = patch.NextAiringEpisode
|
||||
}
|
||||
}
|
||||
|
||||
func applyAnimeCollectionWithRelationsEntryPatch(entry *AnimeCollectionWithRelations_MediaListCollection_Lists_Entries, patch AnimeCollectionEntryPatch) {
|
||||
if patch.Status != nil {
|
||||
entry.Status = patch.Status
|
||||
}
|
||||
if patch.Progress != nil {
|
||||
entry.Progress = patch.Progress
|
||||
}
|
||||
if patch.Score != nil {
|
||||
entry.Score = patch.Score
|
||||
}
|
||||
if patch.Repeat != nil {
|
||||
entry.Repeat = patch.Repeat
|
||||
}
|
||||
if patch.AiredEpisodes != nil {
|
||||
entry.Media.Episodes = patch.AiredEpisodes
|
||||
}
|
||||
}
|
||||
|
||||
func findAnimeCollectionEntry(collection *AnimeCollection, mediaID int) (*AnimeCollection_MediaListCollection_Lists_Entries, *AnimeCollection_MediaListCollection_Lists) {
|
||||
if collection == nil || collection.MediaListCollection == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for _, list := range collection.MediaListCollection.Lists {
|
||||
if list == nil || list.Entries == nil {
|
||||
continue
|
||||
}
|
||||
for _, entry := range list.Entries {
|
||||
if entry != nil && entry.GetMedia().GetID() == mediaID {
|
||||
return entry, list
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func findAnimeCollectionWithRelationsEntry(collection *AnimeCollectionWithRelations, mediaID int) (*AnimeCollectionWithRelations_MediaListCollection_Lists_Entries, *AnimeCollectionWithRelations_MediaListCollection_Lists) {
|
||||
if collection == nil || collection.MediaListCollection == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for _, list := range collection.MediaListCollection.Lists {
|
||||
if list == nil || list.Entries == nil {
|
||||
continue
|
||||
}
|
||||
for _, entry := range list.Entries {
|
||||
if entry != nil && entry.GetMedia().GetID() == mediaID {
|
||||
return entry, list
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func moveAnimeEntryToStatus(collection *AnimeCollection, currentList *AnimeCollection_MediaListCollection_Lists, entry *AnimeCollection_MediaListCollection_Lists_Entries, status MediaListStatus) *AnimeCollection_MediaListCollection_Lists {
|
||||
if currentList != nil && currentList.Status != nil && *currentList.Status == status {
|
||||
return currentList
|
||||
}
|
||||
if currentList != nil {
|
||||
removeAnimeEntry(currentList, entry.GetMedia().GetID())
|
||||
}
|
||||
|
||||
target := ensureAnimeStatusList(collection, status)
|
||||
target.Entries = append(target.Entries, entry)
|
||||
return target
|
||||
}
|
||||
|
||||
func moveAnimeRelationsEntryToStatus(collection *AnimeCollectionWithRelations, currentList *AnimeCollectionWithRelations_MediaListCollection_Lists, entry *AnimeCollectionWithRelations_MediaListCollection_Lists_Entries, status MediaListStatus) *AnimeCollectionWithRelations_MediaListCollection_Lists {
|
||||
if currentList != nil && currentList.Status != nil && *currentList.Status == status {
|
||||
return currentList
|
||||
}
|
||||
if currentList != nil {
|
||||
removeAnimeRelationsEntry(currentList, entry.GetMedia().GetID())
|
||||
}
|
||||
|
||||
target := ensureAnimeRelationsStatusList(collection, status)
|
||||
target.Entries = append(target.Entries, entry)
|
||||
return target
|
||||
}
|
||||
|
||||
func ensureAnimeStatusList(collection *AnimeCollection, status MediaListStatus) *AnimeCollection_MediaListCollection_Lists {
|
||||
if collection.MediaListCollection == nil {
|
||||
collection.MediaListCollection = &AnimeCollection_MediaListCollection{}
|
||||
}
|
||||
|
||||
for _, list := range collection.MediaListCollection.Lists {
|
||||
if list != nil && list.Status != nil && *list.Status == status {
|
||||
if list.Entries == nil {
|
||||
list.Entries = []*AnimeCollection_MediaListCollection_Lists_Entries{}
|
||||
}
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
name := string(status)
|
||||
isCustomList := false
|
||||
list := &AnimeCollection_MediaListCollection_Lists{
|
||||
Status: testPointer(status),
|
||||
Name: &name,
|
||||
IsCustomList: &isCustomList,
|
||||
Entries: []*AnimeCollection_MediaListCollection_Lists_Entries{},
|
||||
}
|
||||
collection.MediaListCollection.Lists = append(collection.MediaListCollection.Lists, list)
|
||||
return list
|
||||
}
|
||||
|
||||
func ensureAnimeRelationsStatusList(collection *AnimeCollectionWithRelations, status MediaListStatus) *AnimeCollectionWithRelations_MediaListCollection_Lists {
|
||||
if collection.MediaListCollection == nil {
|
||||
collection.MediaListCollection = &AnimeCollectionWithRelations_MediaListCollection{}
|
||||
}
|
||||
|
||||
for _, list := range collection.MediaListCollection.Lists {
|
||||
if list != nil && list.Status != nil && *list.Status == status {
|
||||
if list.Entries == nil {
|
||||
list.Entries = []*AnimeCollectionWithRelations_MediaListCollection_Lists_Entries{}
|
||||
}
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
name := string(status)
|
||||
isCustomList := false
|
||||
list := &AnimeCollectionWithRelations_MediaListCollection_Lists{
|
||||
Status: testPointer(status),
|
||||
Name: &name,
|
||||
IsCustomList: &isCustomList,
|
||||
Entries: []*AnimeCollectionWithRelations_MediaListCollection_Lists_Entries{},
|
||||
}
|
||||
collection.MediaListCollection.Lists = append(collection.MediaListCollection.Lists, list)
|
||||
return list
|
||||
}
|
||||
|
||||
func removeAnimeEntry(list *AnimeCollection_MediaListCollection_Lists, mediaID int) {
|
||||
for idx, entry := range list.GetEntries() {
|
||||
if entry != nil && entry.GetMedia().GetID() == mediaID {
|
||||
list.Entries = append(list.Entries[:idx], list.Entries[idx+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeAnimeRelationsEntry(list *AnimeCollectionWithRelations_MediaListCollection_Lists, mediaID int) {
|
||||
for idx, entry := range list.GetEntries() {
|
||||
if entry != nil && entry.GetMedia().GetID() == mediaID {
|
||||
list.Entries = append(list.Entries[:idx], list.Entries[idx+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testPointer[T any](value T) *T {
|
||||
return &value
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package metadata_provider
|
||||
|
||||
import (
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/util"
|
||||
"seanime/internal/util/filecache"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func GetFakeProvider(t *testing.T, db *db.Database) Provider {
|
||||
filecacher, err := filecache.NewCacher(t.TempDir())
|
||||
require.NoError(t, err)
|
||||
return NewProvider(&NewProviderImplOptions{
|
||||
Logger: util.NewLogger(),
|
||||
FileCacher: filecacher,
|
||||
Database: db,
|
||||
ExtensionBankRef: util.NewRef(extension.NewUnifiedBank()),
|
||||
})
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
func TestProvider(t *testing.T) {
|
||||
|
||||
metadataProvider := GetFakeProvider(t, nil)
|
||||
metadataProvider := NewTestProvider(t, nil)
|
||||
|
||||
tests := []struct {
|
||||
platform metadata.Platform
|
||||
|
||||
24
internal/api/metadata_provider/test.go
Normal file
24
internal/api/metadata_provider/test.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package metadata_provider
|
||||
|
||||
import (
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/util"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func NewTestProvider(t *testing.T, db *db.Database) Provider {
|
||||
t.Helper()
|
||||
|
||||
return NewTestProviderWithEnv(testutil.NewTestEnv(t), db)
|
||||
}
|
||||
|
||||
func NewTestProviderWithEnv(env *testutil.TestEnv, db *db.Database) Provider {
|
||||
return NewProvider(&NewProviderImplOptions{
|
||||
Logger: env.Logger(),
|
||||
FileCacher: env.NewCacher("metadata-provider"),
|
||||
Database: db,
|
||||
ExtensionBankRef: util.NewRef(extension.NewUnifiedBank()),
|
||||
})
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
package continuity
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/util"
|
||||
"seanime/internal/util/filecache"
|
||||
"testing"
|
||||
|
||||
@@ -12,18 +9,10 @@ import (
|
||||
)
|
||||
|
||||
func TestHistoryItems(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t)
|
||||
|
||||
logger := util.NewLogger()
|
||||
|
||||
tempDir := t.TempDir()
|
||||
t.Log(tempDir)
|
||||
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
require.NoError(t, err)
|
||||
|
||||
cacher, err := filecache.NewCacher(filepath.Join(tempDir, "cache"))
|
||||
require.NoError(t, err)
|
||||
env := testutil.NewTestEnv(t)
|
||||
logger := env.Logger()
|
||||
database := env.NewDatabase("")
|
||||
cacher := env.NewCacher("continuity")
|
||||
|
||||
manager := NewManager(&NewManagerOptions{
|
||||
FileCacher: cacher,
|
||||
@@ -32,6 +21,8 @@ func TestHistoryItems(t *testing.T) {
|
||||
})
|
||||
require.NotNil(t, manager)
|
||||
|
||||
var err error
|
||||
|
||||
var mediaIds = make([]int, MaxWatchHistoryItems+1)
|
||||
for i := 0; i < MaxWatchHistoryItems+1; i++ {
|
||||
mediaIds[i] = i + 1
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package continuity
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"path/filepath"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/util"
|
||||
"seanime/internal/util/filecache"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func GetMockManager(t *testing.T, db *db.Database) *Manager {
|
||||
func NewTestManager(t *testing.T, db *db.Database) *Manager {
|
||||
logger := util.NewLogger()
|
||||
cacher, err := filecache.NewCacher(filepath.Join(t.TempDir(), "cache"))
|
||||
require.NoError(t, err)
|
||||
@@ -1,50 +0,0 @@
|
||||
package debrid_client
|
||||
|
||||
import (
|
||||
"seanime/internal/api/anilist"
|
||||
"seanime/internal/api/metadata_provider"
|
||||
"seanime/internal/continuity"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/events"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/library/playbackmanager"
|
||||
"seanime/internal/platforms/anilist_platform"
|
||||
"seanime/internal/util"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func GetMockRepository(t *testing.T, db *db.Database) *Repository {
|
||||
logger := util.NewLogger()
|
||||
wsEventManager := events.NewWSEventManager(logger)
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
anilistClientRef := util.NewRef(anilistClient)
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
platform := anilist_platform.NewAnilistPlatform(anilistClientRef, extensionBankRef, logger, db)
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, db)
|
||||
platformRef := util.NewRef(platform)
|
||||
metadataProviderRef := util.NewRef(metadataProvider)
|
||||
playbackManager := playbackmanager.New(&playbackmanager.NewPlaybackManagerOptions{
|
||||
WSEventManager: wsEventManager,
|
||||
Logger: logger,
|
||||
PlatformRef: platformRef,
|
||||
MetadataProviderRef: metadataProviderRef,
|
||||
Database: db,
|
||||
RefreshAnimeCollectionFunc: func() {
|
||||
// Do nothing
|
||||
},
|
||||
DiscordPresence: nil,
|
||||
IsOfflineRef: util.NewRef(false),
|
||||
ContinuityManager: continuity.GetMockManager(t, db),
|
||||
})
|
||||
|
||||
r := NewRepository(&NewRepositoryOptions{
|
||||
Logger: logger,
|
||||
WSEventManager: wsEventManager,
|
||||
Database: db,
|
||||
MetadataProviderRef: metadataProviderRef,
|
||||
PlatformRef: platformRef,
|
||||
PlaybackManager: playbackManager,
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"seanime/internal/testutil"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -30,6 +31,20 @@ func PrintPathStructure(path string, indent string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeFixtureFile(t testing.TB, root string, fixturePath string) string {
|
||||
t.Helper()
|
||||
|
||||
target := filepath.Join(root, testutil.FixtureRelPath(fixturePath))
|
||||
if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
|
||||
t.Fatalf("failed to create directory: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(target, []byte("dummy content"), 0644); err != nil {
|
||||
t.Fatalf("failed to create file %s: %v", target, err)
|
||||
}
|
||||
|
||||
return target
|
||||
}
|
||||
|
||||
func TestCreateTempDir(t *testing.T) {
|
||||
|
||||
files := []string{
|
||||
@@ -39,13 +54,7 @@ func TestCreateTempDir(t *testing.T) {
|
||||
|
||||
root := t.TempDir()
|
||||
for _, file := range files {
|
||||
path := filepath.Join(root, file)
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
||||
t.Fatalf("failed to create directory: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(path, []byte("dummy content"), 0644); err != nil {
|
||||
t.Fatalf("failed to create file %s: %v", path, err)
|
||||
}
|
||||
writeFixtureFile(t, root, file)
|
||||
}
|
||||
defer os.RemoveAll(root)
|
||||
|
||||
@@ -172,13 +181,7 @@ func TestMoveContentsTo(t *testing.T) {
|
||||
// Create the source directory structure
|
||||
root := t.TempDir()
|
||||
for _, file := range tt.files {
|
||||
path := filepath.Join(root, file)
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
||||
t.Fatalf("failed to create directory: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(path, []byte("dummy content"), 0644); err != nil {
|
||||
t.Fatalf("failed to create file %s: %v", path, err)
|
||||
}
|
||||
writeFixtureFile(t, root, file)
|
||||
}
|
||||
|
||||
PrintPathStructure(root, "")
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"os"
|
||||
"seanime/internal/api/anilist"
|
||||
"seanime/internal/api/metadata_provider"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/platforms/anilist_platform"
|
||||
"seanime/internal/testutil"
|
||||
@@ -17,18 +16,18 @@ import (
|
||||
)
|
||||
|
||||
func TestGojaAnimeTorrentProvider(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
env := testutil.NewTestEnv(t)
|
||||
|
||||
logger := util.NewLogger()
|
||||
database, _ := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
database := env.MustNewDatabase(logger)
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
anilistClient := anilist.NewTestAnilistClient()
|
||||
anilistClientRef := util.NewRef(anilistClient)
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
platform := anilist_platform.NewAnilistPlatform(anilistClientRef, extensionBankRef, logger, database)
|
||||
platformRef := util.NewRef(platform)
|
||||
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
metadataProvider := metadata_provider.NewTestProvider(t, database)
|
||||
metadataProviderRef := util.NewRef(metadataProvider)
|
||||
|
||||
repo := NewPlaygroundRepository(logger, platformRef, metadataProviderRef)
|
||||
|
||||
@@ -4,10 +4,10 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"seanime/internal/api/anilist"
|
||||
"seanime/internal/api/metadata_provider"
|
||||
"seanime/internal/continuity"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/events"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/goja/goja_runtime"
|
||||
@@ -30,14 +30,24 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TODO(Test): Replace with in-memory stubs
|
||||
var (
|
||||
testDocumentsDir = "/Users/rahim/Documents"
|
||||
testDocumentCollectionDir = "/Users/rahim/Documents/collection"
|
||||
testVideoPath = "/Users/rahim/Documents/collection/Bocchi the Rock/[ASW] Bocchi the Rock! - 01 [1080p HEVC][EDC91675].mkv"
|
||||
type pluginTestPaths struct {
|
||||
DocumentsDir string
|
||||
CollectionDir string
|
||||
}
|
||||
|
||||
tempTestDir = "$TEMP/test"
|
||||
)
|
||||
func newPluginTestPaths(t testing.TB) pluginTestPaths {
|
||||
t.Helper()
|
||||
|
||||
env := testutil.NewTestEnv(t)
|
||||
documentsDir := env.MustMkdir("Documents")
|
||||
collectionDir := env.MustMkdir("Documents", "collection")
|
||||
env.MustWriteFixtureFile("/Documents/collection/fixture.txt", []byte("fixture"))
|
||||
|
||||
return pluginTestPaths{
|
||||
DocumentsDir: documentsDir,
|
||||
CollectionDir: collectionDir,
|
||||
}
|
||||
}
|
||||
|
||||
// TestPluginOptions contains options for initializing a test plugin
|
||||
type TestPluginOptions struct {
|
||||
@@ -63,9 +73,9 @@ func DefaultTestPluginOptions() TestPluginOptions {
|
||||
|
||||
// InitTestPlugin initializes a test plugin with the given options
|
||||
func InitTestPlugin(t testing.TB, opts TestPluginOptions) (*GojaPlugin, *zerolog.Logger, *goja_runtime.Manager, *anilist_platform.AnilistPlatform, events.WSEventManagerInterface, error) {
|
||||
cfg := testutil.LoadConfig(t)
|
||||
env := testutil.NewTestEnv(t)
|
||||
if opts.SetupHooks {
|
||||
cfg = testutil.InitTestProvider(t, testutil.Anilist())
|
||||
env = testutil.NewTestEnv(t, testutil.Anilist())
|
||||
}
|
||||
|
||||
ext := &extension.Extension{
|
||||
@@ -84,10 +94,9 @@ func InitTestPlugin(t testing.TB, opts TestPluginOptions) (*GojaPlugin, *zerolog
|
||||
ext.Plugin.Permissions.Allow = opts.Permissions.Allow
|
||||
|
||||
logger := util.NewLogger()
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
require.NoError(t, err)
|
||||
database := env.MustNewDatabase(logger)
|
||||
wsEventManager := events.NewMockWSEventManager(logger)
|
||||
anilistClientRef := util.NewRef[anilist.AnilistClient](anilist.NewMockAnilistClient())
|
||||
anilistClientRef := util.NewRef[anilist.AnilistClient](anilist.NewFixtureAnilistClient())
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
anilistPlatform := anilist_platform.NewAnilistPlatform(anilistClientRef, extensionBankRef, logger, database).(*anilist_platform.AnilistPlatform)
|
||||
anilistPlatformRef := util.NewRef[platform.Platform](anilistPlatform)
|
||||
@@ -141,7 +150,6 @@ func TestGojaPluginAnime(t *testing.T) {
|
||||
})
|
||||
}
|
||||
`
|
||||
|
||||
opts := DefaultTestPluginOptions()
|
||||
opts.Payload = payload
|
||||
opts.Permissions = extension.PluginPermissions{
|
||||
@@ -150,10 +158,9 @@ func TestGojaPluginAnime(t *testing.T) {
|
||||
extension.PluginPermissionDatabase,
|
||||
},
|
||||
}
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
env := testutil.NewTestEnv(t, testutil.Anilist())
|
||||
logger := util.NewLogger()
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
require.NoError(t, err)
|
||||
database := env.MustNewDatabase(logger)
|
||||
|
||||
metadataProvider := metadata_provider.NewProvider(&metadata_provider.NewProviderImplOptions{
|
||||
Logger: logger,
|
||||
@@ -185,6 +192,9 @@ func TestGojaPluginAnime(t *testing.T) {
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
func TestGojaPluginMpv(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.MediaPlayer())
|
||||
sampleVideoPath := testutil.RequireSampleVideoPath(t)
|
||||
|
||||
payload := fmt.Sprintf(`
|
||||
function init() {
|
||||
|
||||
@@ -213,7 +223,7 @@ function init() {
|
||||
});
|
||||
|
||||
}
|
||||
`, testVideoPath)
|
||||
`, sampleVideoPath)
|
||||
|
||||
playbackManager, _, err := getPlaybackManager(t)
|
||||
require.NoError(t, err)
|
||||
@@ -243,18 +253,18 @@ function init() {
|
||||
// Test that the plugin cannot access paths that are not allowed
|
||||
// $os.readDir should throw an error
|
||||
func TestGojaPluginPathNotAllowed(t *testing.T) {
|
||||
paths := newPluginTestPaths(t)
|
||||
homeDir, err := os.UserHomeDir()
|
||||
require.NoError(t, err)
|
||||
|
||||
payload := fmt.Sprintf(`
|
||||
function init() {
|
||||
$ui.register((ctx) => {
|
||||
|
||||
const tempDir = $os.tempDir();
|
||||
console.log("Temp dir", tempDir);
|
||||
|
||||
const dirPath = "%s";
|
||||
const entries = $os.readDir(dirPath);
|
||||
const dirPath = %q;
|
||||
$os.readDir(dirPath);
|
||||
});
|
||||
}
|
||||
`, testDocumentCollectionDir)
|
||||
`, homeDir)
|
||||
|
||||
opts := DefaultTestPluginOptions()
|
||||
opts.Payload = payload
|
||||
@@ -263,7 +273,7 @@ function init() {
|
||||
extension.PluginPermissionSystem,
|
||||
},
|
||||
Allow: extension.PluginAllowlist{
|
||||
ReadPaths: []string{"$TEMP/*", testDocumentsDir},
|
||||
ReadPaths: []string{paths.DocumentsDir},
|
||||
WritePaths: []string{"$TEMP/*"},
|
||||
},
|
||||
}
|
||||
@@ -279,6 +289,9 @@ function init() {
|
||||
|
||||
// Test that the plugin can play a video and listen to events
|
||||
func TestGojaPluginPlaybackEvents(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.MediaPlayer())
|
||||
sampleVideoPath := testutil.RequireSampleVideoPath(t)
|
||||
|
||||
payload := fmt.Sprintf(`
|
||||
function init() {
|
||||
|
||||
@@ -298,7 +311,7 @@ function init() {
|
||||
});
|
||||
|
||||
}
|
||||
`, testVideoPath)
|
||||
`, sampleVideoPath)
|
||||
|
||||
playbackManager, _, err := getPlaybackManager(t)
|
||||
require.NoError(t, err)
|
||||
@@ -801,25 +814,21 @@ func TestGojaPluginStorage2(t *testing.T) {
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////s
|
||||
|
||||
func getPlaybackManager(t *testing.T) (*playbackmanager.PlaybackManager, *anilist.AnimeCollection, error) {
|
||||
cfg := testutil.LoadConfig(t)
|
||||
env := testutil.NewTestEnv(t)
|
||||
|
||||
logger := util.NewLogger()
|
||||
|
||||
wsEventManager := events.NewMockWSEventManager(logger)
|
||||
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("error while creating database, %v", err)
|
||||
}
|
||||
database := env.MustNewDatabase(logger)
|
||||
|
||||
filecacher, err := filecache.NewCacher(t.TempDir())
|
||||
require.NoError(t, err)
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
anilistClient := anilist.NewTestAnilistClient()
|
||||
anilistClientRef := util.NewRef(anilistClient)
|
||||
anilistPlatform := anilist_platform.NewAnilistPlatform(anilistClientRef, util.NewRef(extension.NewUnifiedBank()), logger, database)
|
||||
animeCollection, err := anilistPlatform.GetAnimeCollection(t.Context(), true)
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
metadataProvider := metadata_provider.NewTestProvider(t, database)
|
||||
require.NoError(t, err)
|
||||
continuityManager := continuity.NewManager(&continuity.NewManagerOptions{
|
||||
FileCacher: filecacher,
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/library/anime"
|
||||
"seanime/internal/platforms/anilist_platform"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/util"
|
||||
"testing"
|
||||
|
||||
@@ -15,16 +14,15 @@ import (
|
||||
)
|
||||
|
||||
func TestNewLibraryCollection(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
logger := util.NewLogger()
|
||||
|
||||
database, err := db.NewDatabase(t.TempDir(), "test", logger)
|
||||
assert.NoError(t, err)
|
||||
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
metadataProvider := metadata_provider.NewTestProvider(t, database)
|
||||
//wsEventManager := events.NewMockWSEventManager(logger)
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
anilistClient := anilist.NewTestAnilistClient()
|
||||
anilistPlatform := anilist_platform.NewAnilistPlatform(util.NewRef(anilistClient), util.NewRef(extension.NewUnifiedBank()), logger, database)
|
||||
|
||||
animeCollection, err := anilistPlatform.GetAnimeCollection(t.Context(), false)
|
||||
@@ -38,18 +36,23 @@ func TestNewLibraryCollection(t *testing.T) {
|
||||
// Sousou no Frieren
|
||||
// 7 episodes downloaded, 4 watched
|
||||
mediaId := 154587
|
||||
lfs = append(lfs, anime.MockHydratedLocalFiles(
|
||||
anime.MockGenerateHydratedLocalFileGroupOptions("E:/Anime", "E:\\Anime\\Sousou no Frieren\\[SubsPlease] Sousou no Frieren - %ep (1080p) [F02B9CEE].mkv", mediaId, []anime.MockHydratedLocalFileWrapperOptionsMetadata{
|
||||
{MetadataEpisode: 1, MetadataAniDbEpisode: "1", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 2, MetadataAniDbEpisode: "2", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 3, MetadataAniDbEpisode: "3", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 4, MetadataAniDbEpisode: "4", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 5, MetadataAniDbEpisode: "5", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 6, MetadataAniDbEpisode: "6", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 7, MetadataAniDbEpisode: "7", MetadataType: anime.LocalFileTypeMain},
|
||||
}),
|
||||
lfs = append(lfs, anime.NewTestLocalFiles(
|
||||
anime.TestLocalFileGroup{
|
||||
LibraryPath: "E:/Anime",
|
||||
FilePathTemplate: "E:\\Anime\\Sousou no Frieren\\[SubsPlease] Sousou no Frieren - %ep (1080p) [F02B9CEE].mkv",
|
||||
MediaID: mediaId,
|
||||
Episodes: []anime.TestLocalFileEpisode{
|
||||
{Episode: 1, AniDBEpisode: "1", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 2, AniDBEpisode: "2", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 3, AniDBEpisode: "3", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 4, AniDBEpisode: "4", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 5, AniDBEpisode: "5", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 6, AniDBEpisode: "6", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 7, AniDBEpisode: "7", Type: anime.LocalFileTypeMain},
|
||||
},
|
||||
},
|
||||
)...)
|
||||
anilist.TestModifyAnimeCollectionEntry(animeCollection, mediaId, anilist.TestModifyAnimeCollectionEntryInput{
|
||||
anilist.PatchAnimeCollectionEntry(animeCollection, mediaId, anilist.AnimeCollectionEntryPatch{
|
||||
Status: new(anilist.MediaListStatusCurrent),
|
||||
Progress: new(4), // Mock progress
|
||||
})
|
||||
@@ -57,30 +60,40 @@ func TestNewLibraryCollection(t *testing.T) {
|
||||
// One Piece
|
||||
// Downloaded 1070-1075 but only watched up until 1060
|
||||
mediaId = 21
|
||||
lfs = append(lfs, anime.MockHydratedLocalFiles(
|
||||
anime.MockGenerateHydratedLocalFileGroupOptions("E:/Anime", "E:\\Anime\\One Piece\\[SubsPlease] One Piece - %ep (1080p) [F02B9CEE].mkv", mediaId, []anime.MockHydratedLocalFileWrapperOptionsMetadata{
|
||||
{MetadataEpisode: 1070, MetadataAniDbEpisode: "1070", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 1071, MetadataAniDbEpisode: "1071", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 1072, MetadataAniDbEpisode: "1072", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 1073, MetadataAniDbEpisode: "1073", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 1074, MetadataAniDbEpisode: "1074", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 1075, MetadataAniDbEpisode: "1075", MetadataType: anime.LocalFileTypeMain},
|
||||
}),
|
||||
lfs = append(lfs, anime.NewTestLocalFiles(
|
||||
anime.TestLocalFileGroup{
|
||||
LibraryPath: "E:/Anime",
|
||||
FilePathTemplate: "E:\\Anime\\One Piece\\[SubsPlease] One Piece - %ep (1080p) [F02B9CEE].mkv",
|
||||
MediaID: mediaId,
|
||||
Episodes: []anime.TestLocalFileEpisode{
|
||||
{Episode: 1070, AniDBEpisode: "1070", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 1071, AniDBEpisode: "1071", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 1072, AniDBEpisode: "1072", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 1073, AniDBEpisode: "1073", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 1074, AniDBEpisode: "1074", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 1075, AniDBEpisode: "1075", Type: anime.LocalFileTypeMain},
|
||||
},
|
||||
},
|
||||
)...)
|
||||
anilist.TestModifyAnimeCollectionEntry(animeCollection, mediaId, anilist.TestModifyAnimeCollectionEntryInput{
|
||||
anilist.PatchAnimeCollectionEntry(animeCollection, mediaId, anilist.AnimeCollectionEntryPatch{
|
||||
Status: new(anilist.MediaListStatusCurrent),
|
||||
Progress: new(1060), // Mock progress
|
||||
})
|
||||
|
||||
// Add unmatched local files
|
||||
mediaId = 0
|
||||
lfs = append(lfs, anime.MockHydratedLocalFiles(
|
||||
anime.MockGenerateHydratedLocalFileGroupOptions("E:/Anime", "E:\\Anime\\Unmatched\\[SubsPlease] Unmatched - %ep (1080p) [F02B9CEE].mkv", mediaId, []anime.MockHydratedLocalFileWrapperOptionsMetadata{
|
||||
{MetadataEpisode: 1, MetadataAniDbEpisode: "1", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 2, MetadataAniDbEpisode: "2", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 3, MetadataAniDbEpisode: "3", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 4, MetadataAniDbEpisode: "4", MetadataType: anime.LocalFileTypeMain},
|
||||
}),
|
||||
lfs = append(lfs, anime.NewTestLocalFiles(
|
||||
anime.TestLocalFileGroup{
|
||||
LibraryPath: "E:/Anime",
|
||||
FilePathTemplate: "E:\\Anime\\Unmatched\\[SubsPlease] Unmatched - %ep (1080p) [F02B9CEE].mkv",
|
||||
MediaID: mediaId,
|
||||
Episodes: []anime.TestLocalFileEpisode{
|
||||
{Episode: 1, AniDBEpisode: "1", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 2, AniDBEpisode: "2", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 3, AniDBEpisode: "3", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 4, AniDBEpisode: "4", Type: anime.LocalFileTypeMain},
|
||||
},
|
||||
},
|
||||
)...)
|
||||
|
||||
libraryCollection, err := anime.NewLibraryCollection(t.Context(), &anime.NewLibraryCollectionOptions{
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"seanime/internal/api/anilist"
|
||||
"seanime/internal/api/metadata"
|
||||
"seanime/internal/api/metadata_provider"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/library/anime"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/util"
|
||||
@@ -16,15 +15,14 @@ import (
|
||||
)
|
||||
|
||||
func TestNewEntryDownloadInfo(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
env := testutil.NewTestEnv(t)
|
||||
|
||||
logger := util.NewLogger()
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
require.NoError(t, err)
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
database := env.MustNewDatabase(logger)
|
||||
metadataProvider := metadata_provider.NewTestProviderWithEnv(env, database)
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
animeCollection, err := anilistClient.AnimeCollection(context.Background(), &cfg.Provider.AnilistUsername)
|
||||
anilistClient := anilist.NewTestAnilistClient()
|
||||
animeCollection, err := anilistClient.AnimeCollection(context.Background(), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -157,16 +155,14 @@ func TestNewEntryDownloadInfo(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewEntryDownloadInfo2(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
mediaId := 21
|
||||
env := testutil.NewTestEnv(t)
|
||||
|
||||
logger := util.NewLogger()
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
require.NoError(t, err)
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
database := env.MustNewDatabase(logger)
|
||||
metadataProvider := metadata_provider.NewTestProviderWithEnv(env, database)
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
anilistClient := anilist.NewTestAnilistClient()
|
||||
animeCollection, err := anilistClient.AnimeCollection(context.Background(), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/library/anime"
|
||||
"seanime/internal/platforms/anilist_platform"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/util"
|
||||
"testing"
|
||||
|
||||
@@ -17,13 +16,12 @@ import (
|
||||
// TestNewAnimeEntry tests /library/entry endpoint.
|
||||
// /!\ MAKE SURE TO HAVE THE MEDIA ADDED TO YOUR LIST TEST ACCOUNT LISTS
|
||||
func TestNewAnimeEntry(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
logger := util.NewLogger()
|
||||
|
||||
database, err := db.NewDatabase(t.TempDir(), "test", logger)
|
||||
assert.NoError(t, err)
|
||||
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
metadataProvider := metadata_provider.NewTestProvider(t, database)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -36,14 +34,19 @@ func TestNewAnimeEntry(t *testing.T) {
|
||||
{
|
||||
name: "Sousou no Frieren",
|
||||
mediaId: 154587,
|
||||
localFiles: anime.MockHydratedLocalFiles(
|
||||
anime.MockGenerateHydratedLocalFileGroupOptions("E:/Anime", "E:\\Anime\\Sousou no Frieren\\[SubsPlease] Sousou no Frieren - %ep (1080p) [F02B9CEE].mkv", 154587, []anime.MockHydratedLocalFileWrapperOptionsMetadata{
|
||||
{MetadataEpisode: 1, MetadataAniDbEpisode: "1", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 2, MetadataAniDbEpisode: "2", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 3, MetadataAniDbEpisode: "3", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 4, MetadataAniDbEpisode: "4", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 5, MetadataAniDbEpisode: "5", MetadataType: anime.LocalFileTypeMain},
|
||||
}),
|
||||
localFiles: anime.NewTestLocalFiles(
|
||||
anime.TestLocalFileGroup{
|
||||
LibraryPath: "E:/Anime",
|
||||
FilePathTemplate: "E:\\Anime\\Sousou no Frieren\\[SubsPlease] Sousou no Frieren - %ep (1080p) [F02B9CEE].mkv",
|
||||
MediaID: 154587,
|
||||
Episodes: []anime.TestLocalFileEpisode{
|
||||
{Episode: 1, AniDBEpisode: "1", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 2, AniDBEpisode: "2", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 3, AniDBEpisode: "3", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 4, AniDBEpisode: "4", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 5, AniDBEpisode: "5", Type: anime.LocalFileTypeMain},
|
||||
},
|
||||
},
|
||||
),
|
||||
currentProgress: 4,
|
||||
expectedNextEpisodeNumber: 5,
|
||||
@@ -52,22 +55,27 @@ func TestNewAnimeEntry(t *testing.T) {
|
||||
{
|
||||
name: "Mushoku Tensei II Isekai Ittara Honki Dasu",
|
||||
mediaId: 146065,
|
||||
localFiles: anime.MockHydratedLocalFiles(
|
||||
anime.MockGenerateHydratedLocalFileGroupOptions("E:/Anime", "E:/Anime/Mushoku Tensei II Isekai Ittara Honki Dasu/[SubsPlease] Mushoku Tensei S2 - 00 (1080p) [9C362DC3].mkv", 146065, []anime.MockHydratedLocalFileWrapperOptionsMetadata{
|
||||
{MetadataEpisode: 0, MetadataAniDbEpisode: "S1", MetadataType: anime.LocalFileTypeMain}, // Special episode
|
||||
{MetadataEpisode: 1, MetadataAniDbEpisode: "1", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 2, MetadataAniDbEpisode: "2", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 3, MetadataAniDbEpisode: "3", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 4, MetadataAniDbEpisode: "4", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 5, MetadataAniDbEpisode: "5", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 6, MetadataAniDbEpisode: "6", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 7, MetadataAniDbEpisode: "7", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 8, MetadataAniDbEpisode: "8", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 9, MetadataAniDbEpisode: "9", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 10, MetadataAniDbEpisode: "10", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 11, MetadataAniDbEpisode: "11", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 12, MetadataAniDbEpisode: "12", MetadataType: anime.LocalFileTypeMain},
|
||||
}),
|
||||
localFiles: anime.NewTestLocalFiles(
|
||||
anime.TestLocalFileGroup{
|
||||
LibraryPath: "E:/Anime",
|
||||
FilePathTemplate: "E:/Anime/Mushoku Tensei II Isekai Ittara Honki Dasu/[SubsPlease] Mushoku Tensei S2 - 00 (1080p) [9C362DC3].mkv",
|
||||
MediaID: 146065,
|
||||
Episodes: []anime.TestLocalFileEpisode{
|
||||
{Episode: 0, AniDBEpisode: "S1", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 1, AniDBEpisode: "1", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 2, AniDBEpisode: "2", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 3, AniDBEpisode: "3", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 4, AniDBEpisode: "4", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 5, AniDBEpisode: "5", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 6, AniDBEpisode: "6", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 7, AniDBEpisode: "7", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 8, AniDBEpisode: "8", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 9, AniDBEpisode: "9", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 10, AniDBEpisode: "10", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 11, AniDBEpisode: "11", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 12, AniDBEpisode: "12", Type: anime.LocalFileTypeMain},
|
||||
},
|
||||
},
|
||||
),
|
||||
currentProgress: 0,
|
||||
expectedNextEpisodeNumber: 0,
|
||||
@@ -75,7 +83,7 @@ func TestNewAnimeEntry(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
anilistClient := anilist.NewTestAnilistClient()
|
||||
anilistPlatform := anilist_platform.NewAnilistPlatform(util.NewRef(anilistClient), util.NewRef(extension.NewUnifiedBank()), logger, database)
|
||||
animeCollection, err := anilistPlatform.GetAnimeCollection(t.Context(), false)
|
||||
if err != nil {
|
||||
@@ -86,7 +94,7 @@ func TestNewAnimeEntry(t *testing.T) {
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
anilist.TestModifyAnimeCollectionEntry(animeCollection, tt.mediaId, anilist.TestModifyAnimeCollectionEntryInput{
|
||||
anilist.PatchAnimeCollectionEntry(animeCollection, tt.mediaId, anilist.AnimeCollectionEntryPatch{
|
||||
Progress: new(tt.currentProgress), // Mock progress
|
||||
})
|
||||
|
||||
|
||||
@@ -2,32 +2,48 @@ package anime_test
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"seanime/internal/library/anime"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestLocalFileWrapperEntry(t *testing.T) {
|
||||
|
||||
lfs := anime.MockHydratedLocalFiles(
|
||||
anime.MockGenerateHydratedLocalFileGroupOptions("/mnt/anime/", "/mnt/anime/One Piece/One Piece - %ep.mkv", 21, []anime.MockHydratedLocalFileWrapperOptionsMetadata{
|
||||
{MetadataEpisode: 1070, MetadataAniDbEpisode: "1070", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 1071, MetadataAniDbEpisode: "1071", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 1072, MetadataAniDbEpisode: "1072", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 1073, MetadataAniDbEpisode: "1073", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 1074, MetadataAniDbEpisode: "1074", MetadataType: anime.LocalFileTypeMain},
|
||||
}),
|
||||
anime.MockGenerateHydratedLocalFileGroupOptions("/mnt/anime/", "/mnt/anime/Blue Lock/Blue Lock - %ep.mkv", 22222, []anime.MockHydratedLocalFileWrapperOptionsMetadata{
|
||||
{MetadataEpisode: 1, MetadataAniDbEpisode: "1", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 2, MetadataAniDbEpisode: "2", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 3, MetadataAniDbEpisode: "3", MetadataType: anime.LocalFileTypeMain},
|
||||
}),
|
||||
anime.MockGenerateHydratedLocalFileGroupOptions("/mnt/anime/", "/mnt/anime/Kimi ni Todoke/Kimi ni Todoke - %ep.mkv", 9656, []anime.MockHydratedLocalFileWrapperOptionsMetadata{
|
||||
{MetadataEpisode: 0, MetadataAniDbEpisode: "S1", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 1, MetadataAniDbEpisode: "1", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 2, MetadataAniDbEpisode: "2", MetadataType: anime.LocalFileTypeMain},
|
||||
}),
|
||||
lfs := anime.NewTestLocalFiles(
|
||||
anime.TestLocalFileGroup{
|
||||
LibraryPath: "/mnt/anime/",
|
||||
FilePathTemplate: "/mnt/anime/One Piece/One Piece - %ep.mkv",
|
||||
MediaID: 21,
|
||||
Episodes: []anime.TestLocalFileEpisode{
|
||||
{Episode: 1070, AniDBEpisode: "1070", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 1071, AniDBEpisode: "1071", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 1072, AniDBEpisode: "1072", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 1073, AniDBEpisode: "1073", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 1074, AniDBEpisode: "1074", Type: anime.LocalFileTypeMain},
|
||||
},
|
||||
},
|
||||
anime.TestLocalFileGroup{
|
||||
LibraryPath: "/mnt/anime/",
|
||||
FilePathTemplate: "/mnt/anime/Blue Lock/Blue Lock - %ep.mkv",
|
||||
MediaID: 22222,
|
||||
Episodes: []anime.TestLocalFileEpisode{
|
||||
{Episode: 1, AniDBEpisode: "1", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 2, AniDBEpisode: "2", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 3, AniDBEpisode: "3", Type: anime.LocalFileTypeMain},
|
||||
},
|
||||
},
|
||||
anime.TestLocalFileGroup{
|
||||
LibraryPath: "/mnt/anime/",
|
||||
FilePathTemplate: "/mnt/anime/Kimi ni Todoke/Kimi ni Todoke - %ep.mkv",
|
||||
MediaID: 9656,
|
||||
Episodes: []anime.TestLocalFileEpisode{
|
||||
{Episode: 0, AniDBEpisode: "S1", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 1, AniDBEpisode: "1", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 2, AniDBEpisode: "2", Type: anime.LocalFileTypeMain},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
@@ -100,17 +116,27 @@ func TestLocalFileWrapperEntry(t *testing.T) {
|
||||
|
||||
func TestLocalFileWrapperEntryProgressNumber(t *testing.T) {
|
||||
|
||||
lfs := anime.MockHydratedLocalFiles(
|
||||
anime.MockGenerateHydratedLocalFileGroupOptions("/mnt/anime/", "/mnt/anime/Kimi ni Todoke/Kimi ni Todoke - %ep.mkv", 9656, []anime.MockHydratedLocalFileWrapperOptionsMetadata{
|
||||
{MetadataEpisode: 0, MetadataAniDbEpisode: "S1", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 1, MetadataAniDbEpisode: "1", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 2, MetadataAniDbEpisode: "2", MetadataType: anime.LocalFileTypeMain},
|
||||
}),
|
||||
anime.MockGenerateHydratedLocalFileGroupOptions("/mnt/anime/", "/mnt/anime/Kimi ni Todoke/Kimi ni Todoke - %ep.mkv", 9656_2, []anime.MockHydratedLocalFileWrapperOptionsMetadata{
|
||||
{MetadataEpisode: 1, MetadataAniDbEpisode: "S1", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 2, MetadataAniDbEpisode: "1", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 3, MetadataAniDbEpisode: "2", MetadataType: anime.LocalFileTypeMain},
|
||||
}),
|
||||
lfs := anime.NewTestLocalFiles(
|
||||
anime.TestLocalFileGroup{
|
||||
LibraryPath: "/mnt/anime/",
|
||||
FilePathTemplate: "/mnt/anime/Kimi ni Todoke/Kimi ni Todoke - %ep.mkv",
|
||||
MediaID: 9656,
|
||||
Episodes: []anime.TestLocalFileEpisode{
|
||||
{Episode: 0, AniDBEpisode: "S1", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 1, AniDBEpisode: "1", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 2, AniDBEpisode: "2", Type: anime.LocalFileTypeMain},
|
||||
},
|
||||
},
|
||||
anime.TestLocalFileGroup{
|
||||
LibraryPath: "/mnt/anime/",
|
||||
FilePathTemplate: "/mnt/anime/Kimi ni Todoke/Kimi ni Todoke - %ep.mkv",
|
||||
MediaID: 9656_2,
|
||||
Episodes: []anime.TestLocalFileEpisode{
|
||||
{Episode: 1, AniDBEpisode: "S1", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 2, AniDBEpisode: "1", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 3, AniDBEpisode: "2", Type: anime.LocalFileTypeMain},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
|
||||
@@ -23,9 +23,9 @@ func TestNewMissingEpisodes(t *testing.T) {
|
||||
logger := util.NewLogger()
|
||||
database, _ := db.NewDatabase(t.TempDir(), "test", logger)
|
||||
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
metadataProvider := metadata_provider.NewTestProvider(t, database)
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
anilistClient := anilist.NewTestAnilistClient()
|
||||
animeCollection, err := anilistClient.AnimeCollection(context.Background(), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -45,14 +45,19 @@ func TestNewMissingEpisodes(t *testing.T) {
|
||||
// So we should expect to see 5 missing episodes
|
||||
name: "Sousou no Frieren, missing 5 episodes",
|
||||
mediaId: 154587,
|
||||
localFiles: anime.MockHydratedLocalFiles(
|
||||
anime.MockGenerateHydratedLocalFileGroupOptions("E:/Anime", "E:\\Anime\\Sousou no Frieren\\[SubsPlease] Sousou no Frieren - %ep (1080p) [F02B9CEE].mkv", 154587, []anime.MockHydratedLocalFileWrapperOptionsMetadata{
|
||||
{MetadataEpisode: 1, MetadataAniDbEpisode: "1", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 2, MetadataAniDbEpisode: "2", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 3, MetadataAniDbEpisode: "3", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 4, MetadataAniDbEpisode: "4", MetadataType: anime.LocalFileTypeMain},
|
||||
{MetadataEpisode: 5, MetadataAniDbEpisode: "5", MetadataType: anime.LocalFileTypeMain},
|
||||
}),
|
||||
localFiles: anime.NewTestLocalFiles(
|
||||
anime.TestLocalFileGroup{
|
||||
LibraryPath: "E:/Anime",
|
||||
FilePathTemplate: "E:\\Anime\\Sousou no Frieren\\[SubsPlease] Sousou no Frieren - %ep (1080p) [F02B9CEE].mkv",
|
||||
MediaID: 154587,
|
||||
Episodes: []anime.TestLocalFileEpisode{
|
||||
{Episode: 1, AniDBEpisode: "1", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 2, AniDBEpisode: "2", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 3, AniDBEpisode: "3", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 4, AniDBEpisode: "4", Type: anime.LocalFileTypeMain},
|
||||
{Episode: 5, AniDBEpisode: "5", Type: anime.LocalFileTypeMain},
|
||||
},
|
||||
},
|
||||
),
|
||||
mediaAiredEpisodes: 10,
|
||||
currentProgress: 4,
|
||||
@@ -66,7 +71,7 @@ func TestNewMissingEpisodes(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
// Mock Anilist collection
|
||||
anilist.TestModifyAnimeCollectionEntry(animeCollection, tt.mediaId, anilist.TestModifyAnimeCollectionEntryInput{
|
||||
anilist.PatchAnimeCollectionEntry(animeCollection, tt.mediaId, anilist.AnimeCollectionEntryPatch{
|
||||
Progress: new(tt.currentProgress), // Mock progress
|
||||
AiredEpisodes: new(tt.mediaAiredEpisodes),
|
||||
NextAiringEpisode: &anilist.BaseAnime_NextAiringEpisode{
|
||||
|
||||
@@ -5,76 +5,35 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MockHydratedLocalFileOptions struct {
|
||||
FilePath string
|
||||
type TestLocalFileEpisode struct {
|
||||
Episode int
|
||||
AniDBEpisode string
|
||||
Type LocalFileType
|
||||
}
|
||||
|
||||
type TestLocalFileGroup struct {
|
||||
LibraryPath string
|
||||
MediaId int
|
||||
MetadataEpisode int
|
||||
MetadataAniDbEpisode string
|
||||
MetadataType LocalFileType
|
||||
FilePathTemplate string
|
||||
MediaID int
|
||||
Episodes []TestLocalFileEpisode
|
||||
}
|
||||
|
||||
func MockHydratedLocalFile(opts MockHydratedLocalFileOptions) *LocalFile {
|
||||
lf := NewLocalFile(opts.FilePath, opts.LibraryPath)
|
||||
lf.MediaId = opts.MediaId
|
||||
// NewTestLocalFiles expands one or more local-file groups into hydrated LocalFiles.
|
||||
// FilePathTemplate replaces each %ep token with the episode number.
|
||||
func NewTestLocalFiles(groups ...TestLocalFileGroup) []*LocalFile {
|
||||
localFiles := make([]*LocalFile, 0)
|
||||
for _, group := range groups {
|
||||
for _, episode := range group.Episodes {
|
||||
lf := NewLocalFile(strings.ReplaceAll(group.FilePathTemplate, "%ep", strconv.Itoa(episode.Episode)), group.LibraryPath)
|
||||
lf.MediaId = group.MediaID
|
||||
lf.Metadata = &LocalFileMetadata{
|
||||
AniDBEpisode: opts.MetadataAniDbEpisode,
|
||||
Episode: opts.MetadataEpisode,
|
||||
Type: opts.MetadataType,
|
||||
AniDBEpisode: episode.AniDBEpisode,
|
||||
Episode: episode.Episode,
|
||||
Type: episode.Type,
|
||||
}
|
||||
localFiles = append(localFiles, lf)
|
||||
}
|
||||
return lf
|
||||
}
|
||||
|
||||
// MockHydratedLocalFiles creates a slice of LocalFiles based on the provided options
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// MockHydratedLocalFiles(
|
||||
// MockHydratedLocalFileOptions{
|
||||
// FilePath: "/mnt/anime/One Piece/One Piece - 1070.mkv",
|
||||
// LibraryPath: "/mnt/anime/",
|
||||
// MetadataEpisode: 1070,
|
||||
// MetadataAniDbEpisode: "1070",
|
||||
// MetadataType: LocalFileTypeMain,
|
||||
// },
|
||||
// MockHydratedLocalFileOptions{
|
||||
// ...
|
||||
// },
|
||||
// )
|
||||
func MockHydratedLocalFiles(opts ...[]MockHydratedLocalFileOptions) []*LocalFile {
|
||||
lfs := make([]*LocalFile, 0, len(opts))
|
||||
for _, opt := range opts {
|
||||
for _, o := range opt {
|
||||
lfs = append(lfs, MockHydratedLocalFile(o))
|
||||
}
|
||||
}
|
||||
return lfs
|
||||
}
|
||||
|
||||
type MockHydratedLocalFileWrapperOptionsMetadata struct {
|
||||
MetadataEpisode int
|
||||
MetadataAniDbEpisode string
|
||||
MetadataType LocalFileType
|
||||
}
|
||||
|
||||
// MockGenerateHydratedLocalFileGroupOptions generates a slice of MockHydratedLocalFileOptions based on a template string and metadata
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// MockGenerateHydratedLocalFileGroupOptions("/mnt/anime/", "One Piece/One Piece - %ep.mkv", 21, []MockHydratedLocalFileWrapperOptionsMetadata{
|
||||
// {MetadataEpisode: 1070, MetadataAniDbEpisode: "1070", MetadataType: LocalFileTypeMain},
|
||||
// })
|
||||
func MockGenerateHydratedLocalFileGroupOptions(libraryPath string, template string, mId int, m []MockHydratedLocalFileWrapperOptionsMetadata) []MockHydratedLocalFileOptions {
|
||||
opts := make([]MockHydratedLocalFileOptions, 0, len(m))
|
||||
for _, metadata := range m {
|
||||
opts = append(opts, MockHydratedLocalFileOptions{
|
||||
FilePath: strings.ReplaceAll(template, "%ep", strconv.Itoa(metadata.MetadataEpisode)),
|
||||
LibraryPath: libraryPath,
|
||||
MediaId: mId,
|
||||
MetadataEpisode: metadata.MetadataEpisode,
|
||||
MetadataAniDbEpisode: metadata.MetadataAniDbEpisode,
|
||||
MetadataType: metadata.MetadataType,
|
||||
})
|
||||
}
|
||||
return opts
|
||||
return localFiles
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"seanime/internal/debrid/debrid"
|
||||
hibiketorrent "seanime/internal/extension/hibike/torrent"
|
||||
"seanime/internal/library/anime"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/torrent_clients/torrent_client"
|
||||
"seanime/internal/util"
|
||||
"testing"
|
||||
@@ -973,9 +972,7 @@ func TestIsProfileValidChecks(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIntegration(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
anilistClient := anilist.NewTestAnilistClient()
|
||||
animeCollection, err := anilistClient.AnimeCollection(context.Background(), nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -1159,15 +1156,15 @@ func TestIntegration(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Create a new fake
|
||||
fake := &Fake{
|
||||
harness := &TestHarness{
|
||||
GetLatestResults: tt.torrents,
|
||||
SearchResults: tt.torrents,
|
||||
}
|
||||
ad := fake.New(t)
|
||||
ad := harness.New(t)
|
||||
ad.SetAnimeCollection(animeCollection)
|
||||
|
||||
// Add local files to the database
|
||||
_, err = fake.Database.InsertLocalFiles(&models.LocalFiles{Value: []byte("[]")})
|
||||
_, err = harness.Database.InsertLocalFiles(&models.LocalFiles{Value: []byte("[]")})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set user progress
|
||||
@@ -1213,9 +1210,7 @@ func TestIntegration(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDelayIntegration(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
anilistClient := anilist.NewTestAnilistClient()
|
||||
animeCollection, err := anilistClient.AnimeCollection(context.Background(), nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -1345,7 +1340,7 @@ func TestDelayIntegration(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
fake := &Fake{GetLatestResults: tt.torrents, SearchResults: tt.torrents}
|
||||
fake := &TestHarness{GetLatestResults: tt.torrents, SearchResults: tt.torrents}
|
||||
ad := fake.New(t)
|
||||
ad.SetAnimeCollection(animeCollection)
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
func TestComparison(t *testing.T) {
|
||||
database, _ := db.NewDatabase(t.TempDir(), "test", util.NewLogger())
|
||||
ad := AutoDownloader{
|
||||
metadataProviderRef: util.NewRef(metadata_provider.GetFakeProvider(t, database)),
|
||||
metadataProviderRef: util.NewRef(metadata_provider.NewTestProvider(t, database)),
|
||||
settings: &models.AutoDownloaderSettings{
|
||||
EnableSeasonCheck: true,
|
||||
},
|
||||
@@ -142,7 +142,7 @@ func TestComparison(t *testing.T) {
|
||||
func TestComparison2(t *testing.T) {
|
||||
database, _ := db.NewDatabase(t.TempDir(), "test", util.NewLogger())
|
||||
ad := AutoDownloader{
|
||||
metadataProviderRef: util.NewRef(metadata_provider.GetFakeProvider(t, database)),
|
||||
metadataProviderRef: util.NewRef(metadata_provider.NewTestProvider(t, database)),
|
||||
settings: &models.AutoDownloaderSettings{
|
||||
EnableSeasonCheck: true,
|
||||
},
|
||||
@@ -239,7 +239,7 @@ func TestComparison2(t *testing.T) {
|
||||
func TestComparison3(t *testing.T) {
|
||||
database, _ := db.NewDatabase(t.TempDir(), "test", util.NewLogger())
|
||||
ad := AutoDownloader{
|
||||
metadataProviderRef: util.NewRef(metadata_provider.GetFakeProvider(t, database)),
|
||||
metadataProviderRef: util.NewRef(metadata_provider.NewTestProvider(t, database)),
|
||||
settings: &models.AutoDownloaderSettings{
|
||||
EnableSeasonCheck: true,
|
||||
},
|
||||
|
||||
@@ -11,43 +11,40 @@ import (
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/torrents/torrent"
|
||||
"seanime/internal/util"
|
||||
"seanime/internal/util/filecache"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type Fake struct {
|
||||
type TestHarness struct {
|
||||
SearchResults []*hibiketorrent.AnimeTorrent
|
||||
GetLatestResults []*hibiketorrent.AnimeTorrent
|
||||
Database *db.Database
|
||||
}
|
||||
|
||||
type FakeTorrentProvider struct {
|
||||
fake *Fake
|
||||
type TestTorrentProvider struct {
|
||||
harness *TestHarness
|
||||
}
|
||||
|
||||
func (f FakeTorrentProvider) Search(opts hibiketorrent.AnimeSearchOptions) ([]*hibiketorrent.AnimeTorrent, error) {
|
||||
return f.fake.SearchResults, nil
|
||||
func (f TestTorrentProvider) Search(opts hibiketorrent.AnimeSearchOptions) ([]*hibiketorrent.AnimeTorrent, error) {
|
||||
return f.harness.SearchResults, nil
|
||||
}
|
||||
|
||||
func (f FakeTorrentProvider) SmartSearch(opts hibiketorrent.AnimeSmartSearchOptions) ([]*hibiketorrent.AnimeTorrent, error) {
|
||||
return f.fake.SearchResults, nil
|
||||
func (f TestTorrentProvider) SmartSearch(opts hibiketorrent.AnimeSmartSearchOptions) ([]*hibiketorrent.AnimeTorrent, error) {
|
||||
return f.harness.SearchResults, nil
|
||||
}
|
||||
|
||||
func (f FakeTorrentProvider) GetTorrentInfoHash(torrent *hibiketorrent.AnimeTorrent) (string, error) {
|
||||
func (f TestTorrentProvider) GetTorrentInfoHash(torrent *hibiketorrent.AnimeTorrent) (string, error) {
|
||||
return torrent.InfoHash, nil
|
||||
}
|
||||
|
||||
func (f FakeTorrentProvider) GetTorrentMagnetLink(torrent *hibiketorrent.AnimeTorrent) (string, error) {
|
||||
func (f TestTorrentProvider) GetTorrentMagnetLink(torrent *hibiketorrent.AnimeTorrent) (string, error) {
|
||||
return torrent.MagnetLink, nil
|
||||
}
|
||||
|
||||
func (f FakeTorrentProvider) GetLatest() ([]*hibiketorrent.AnimeTorrent, error) {
|
||||
return f.fake.GetLatestResults, nil
|
||||
func (f TestTorrentProvider) GetLatest() ([]*hibiketorrent.AnimeTorrent, error) {
|
||||
return f.harness.GetLatestResults, nil
|
||||
}
|
||||
|
||||
func (f FakeTorrentProvider) GetSettings() hibiketorrent.AnimeProviderSettings {
|
||||
func (f TestTorrentProvider) GetSettings() hibiketorrent.AnimeProviderSettings {
|
||||
return hibiketorrent.AnimeProviderSettings{
|
||||
CanSmartSearch: false,
|
||||
SmartSearchFilters: nil,
|
||||
@@ -56,28 +53,27 @@ func (f FakeTorrentProvider) GetSettings() hibiketorrent.AnimeProviderSettings {
|
||||
}
|
||||
}
|
||||
|
||||
var _ hibiketorrent.AnimeProvider = (*FakeTorrentProvider)(nil)
|
||||
var _ hibiketorrent.AnimeProvider = (*TestTorrentProvider)(nil)
|
||||
|
||||
func (f *Fake) New(t *testing.T) *AutoDownloader {
|
||||
cfg := testutil.LoadConfig(t)
|
||||
func (f *TestHarness) New(t *testing.T) *AutoDownloader {
|
||||
t.Helper()
|
||||
env := testutil.NewTestEnv(t)
|
||||
|
||||
logger := util.NewLogger()
|
||||
database, err := db.NewDatabase("", cfg.Database.Name, logger)
|
||||
require.NoError(t, err)
|
||||
logger := env.Logger()
|
||||
database := env.NewDatabase("")
|
||||
|
||||
f.Database = database
|
||||
|
||||
filecacher, err := filecache.NewCacher(t.TempDir())
|
||||
require.NoError(t, err)
|
||||
filecacher := env.NewCacher("autodownloader")
|
||||
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
|
||||
// Fake Extension
|
||||
provider := FakeTorrentProvider{fake: f}
|
||||
// Test extension
|
||||
provider := TestTorrentProvider{harness: f}
|
||||
ext := extension.NewAnimeTorrentProviderExtension(&extension.Extension{
|
||||
ID: "fake",
|
||||
Type: extension.TypeAnimeTorrentProvider,
|
||||
Name: "Fake Provider",
|
||||
Name: "Test Provider",
|
||||
}, provider)
|
||||
|
||||
extensionBankRef.Get().Set("fake", ext)
|
||||
@@ -1,16 +0,0 @@
|
||||
package filesystem
|
||||
|
||||
import (
|
||||
"seanime/internal/util"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDeleteEmptyDirectories(t *testing.T) {
|
||||
|
||||
path := "E:/ANIME_TEST"
|
||||
|
||||
RemoveEmptyDirectories(path, util.NewLogger())
|
||||
|
||||
t.Log("All empty directories removed successfully.")
|
||||
|
||||
}
|
||||
@@ -2,15 +2,10 @@ package scanner
|
||||
|
||||
import (
|
||||
"seanime/internal/api/anilist"
|
||||
"seanime/internal/api/metadata_provider"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/library/anime"
|
||||
"seanime/internal/library/summary"
|
||||
"seanime/internal/platforms/anilist_platform"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/platforms/platform"
|
||||
"seanime/internal/util"
|
||||
"seanime/internal/util/limiter"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -18,26 +13,12 @@ import (
|
||||
)
|
||||
|
||||
func TestFileHydrator_HydrateMetadata(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
completeAnimeCache := anilist.NewCompleteAnimeCache()
|
||||
anilistRateLimiter := limiter.NewAnilistLimiter()
|
||||
logger := util.NewLogger()
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
require.NoError(t, err)
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
anilistClient := anilist.NewAnilistClient(cfg.Provider.AnilistJwt, "")
|
||||
anilistClientRef := util.NewRef[anilist.AnilistClient](anilistClient)
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
//wsEventManager := events.NewMockWSEventManager(logger)
|
||||
anilistPlatform := anilist_platform.NewAnilistPlatform(anilistClientRef, extensionBankRef, logger, database)
|
||||
anilistPlatform.SetUsername(cfg.Provider.AnilistUsername)
|
||||
animeCollection, err := anilistPlatform.GetAnimeCollectionWithRelations(t.Context())
|
||||
harness := newScannerFixtureHarness(t)
|
||||
logger := harness.Logger
|
||||
animeCollection, err := harness.Platform.GetAnimeCollectionWithRelations(t.Context())
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, animeCollection)
|
||||
|
||||
allMedia := animeCollection.GetAllAnime()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
paths []string
|
||||
@@ -104,6 +85,14 @@ func TestFileHydrator_HydrateMetadata(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
currentStatus := anilist.MediaListStatusCurrent
|
||||
anilist.EnsureAnimeCollectionWithRelationsEntry(
|
||||
animeCollection,
|
||||
tt.expectedMediaId,
|
||||
anilist.AnimeCollectionEntryPatch{Status: ¤tStatus},
|
||||
harness.AnilistClient,
|
||||
)
|
||||
allMedia := animeCollection.GetAllAnime()
|
||||
|
||||
scanLogger, err := NewConsoleScanLogger()
|
||||
if err != nil {
|
||||
@@ -114,11 +103,7 @@ func TestFileHydrator_HydrateMetadata(t *testing.T) {
|
||||
// | Local Files |
|
||||
// +---------------------+
|
||||
|
||||
var lfs []*anime.LocalFile
|
||||
for _, path := range tt.paths {
|
||||
lf := anime.NewLocalFile(path, "E:/Anime")
|
||||
lfs = append(lfs, lf)
|
||||
}
|
||||
lfs := harness.LocalFiles(tt.paths...)
|
||||
|
||||
// +---------------------+
|
||||
// | MediaContainer |
|
||||
@@ -158,10 +143,10 @@ func TestFileHydrator_HydrateMetadata(t *testing.T) {
|
||||
fh := &FileHydrator{
|
||||
LocalFiles: lfs,
|
||||
AllMedia: mc.NormalizedMedia,
|
||||
CompleteAnimeCache: completeAnimeCache,
|
||||
PlatformRef: util.NewRef(anilistPlatform),
|
||||
AnilistRateLimiter: anilistRateLimiter,
|
||||
MetadataProviderRef: util.NewRef(metadataProvider),
|
||||
CompleteAnimeCache: harness.CompleteAnimeCache,
|
||||
PlatformRef: util.NewRef[platform.Platform](harness.Platform),
|
||||
AnilistRateLimiter: harness.AnilistRateLimiter,
|
||||
MetadataProviderRef: util.NewRef(harness.MetadataProvider),
|
||||
Logger: logger,
|
||||
ScanLogger: scanLogger,
|
||||
Config: config,
|
||||
|
||||
@@ -3,14 +3,9 @@ package scanner
|
||||
import (
|
||||
"context"
|
||||
"seanime/internal/api/anilist"
|
||||
"seanime/internal/api/metadata_provider"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/library/anime"
|
||||
"seanime/internal/platforms/anilist_platform"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/platforms/platform"
|
||||
"seanime/internal/util"
|
||||
"seanime/internal/util/limiter"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -18,7 +13,7 @@ import (
|
||||
|
||||
func TestMatcher1(t *testing.T) {
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
anilistClient := anilist.NewTestAnilistClient()
|
||||
animeCollection, err := anilistClient.AnimeCollectionWithRelations(context.Background(), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
@@ -103,15 +98,17 @@ func TestMatcher1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMatcher2(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := anilist.NewAnilistClient(cfg.Provider.AnilistJwt, "")
|
||||
animeCollection, err := anilistClient.AnimeCollectionWithRelations(context.Background(), &cfg.Provider.AnilistUsername)
|
||||
harness := newScannerLiveHarness(t)
|
||||
anilistClient := harness.AnilistClient
|
||||
animeCollection, err := harness.Platform.GetAnimeCollectionWithRelations(t.Context())
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
if animeCollection == nil {
|
||||
t.Fatal("expected anime collection, got nil")
|
||||
}
|
||||
|
||||
dir := "E:/Anime"
|
||||
dir := harness.LibraryDir
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -156,34 +153,12 @@ func TestMatcher2(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
// Add media to collection if it doesn't exist
|
||||
allMedia := animeCollection.GetAllAnime()
|
||||
hasExpectedMediaId := false
|
||||
for _, media := range allMedia {
|
||||
if media.ID == tt.expectedMediaId {
|
||||
hasExpectedMediaId = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasExpectedMediaId {
|
||||
anilist.TestAddAnimeCollectionWithRelationsEntry(animeCollection, tt.expectedMediaId, anilist.TestModifyAnimeCollectionEntryInput{Status: new(anilist.MediaListStatusCurrent)}, anilistClient)
|
||||
allMedia = animeCollection.GetAllAnime()
|
||||
}
|
||||
|
||||
currentStatus := anilist.MediaListStatusCurrent
|
||||
anilist.EnsureAnimeCollectionWithRelationsEntry(animeCollection, tt.expectedMediaId, anilist.AnimeCollectionEntryPatch{Status: ¤tStatus}, anilistClient)
|
||||
for _, otherMediaId := range tt.otherMediaIds {
|
||||
hasOtherMediaId := false
|
||||
for _, media := range allMedia {
|
||||
if media.ID == otherMediaId {
|
||||
hasOtherMediaId = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasOtherMediaId {
|
||||
anilist.TestAddAnimeCollectionWithRelationsEntry(animeCollection, otherMediaId, anilist.TestModifyAnimeCollectionEntryInput{Status: new(anilist.MediaListStatusCurrent)}, anilistClient)
|
||||
allMedia = animeCollection.GetAllAnime()
|
||||
}
|
||||
anilist.EnsureAnimeCollectionWithRelationsEntry(animeCollection, otherMediaId, anilist.AnimeCollectionEntryPatch{Status: ¤tStatus}, anilistClient)
|
||||
}
|
||||
allMedia := animeCollection.GetAllAnime()
|
||||
|
||||
scanLogger, err := NewConsoleScanLogger()
|
||||
if err != nil {
|
||||
@@ -238,15 +213,17 @@ func TestMatcher2(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMatcher3(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := anilist.NewAnilistClient(cfg.Provider.AnilistJwt, "")
|
||||
animeCollection, err := anilistClient.AnimeCollectionWithRelations(context.Background(), &cfg.Provider.AnilistUsername)
|
||||
harness := newScannerLiveHarness(t)
|
||||
anilistClient := harness.AnilistClient
|
||||
animeCollection, err := harness.Platform.GetAnimeCollectionWithRelations(t.Context())
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
if animeCollection == nil {
|
||||
t.Fatal("expected anime collection, got nil")
|
||||
}
|
||||
|
||||
dir := "E:/Anime"
|
||||
dir := harness.LibraryDir
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -856,37 +833,12 @@ func TestMatcher3(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
// Add media to collection if it doesn't exist
|
||||
allMedia := animeCollection.GetAllAnime()
|
||||
|
||||
// Helper to ensure media exists in collection
|
||||
hasMedia := false
|
||||
for _, media := range allMedia {
|
||||
if media.ID == tt.expectedMediaId {
|
||||
hasMedia = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasMedia {
|
||||
anilist.TestAddAnimeCollectionWithRelationsEntry(animeCollection, tt.expectedMediaId, anilist.TestModifyAnimeCollectionEntryInput{Status: new(anilist.MediaListStatusCurrent)}, anilistClient)
|
||||
allMedia = animeCollection.GetAllAnime()
|
||||
}
|
||||
|
||||
// Ensure other media exists
|
||||
currentStatus := anilist.MediaListStatusCurrent
|
||||
anilist.EnsureAnimeCollectionWithRelationsEntry(animeCollection, tt.expectedMediaId, anilist.AnimeCollectionEntryPatch{Status: ¤tStatus}, anilistClient)
|
||||
for _, id := range tt.otherMediaIds {
|
||||
hasMedia := false
|
||||
for _, media := range allMedia {
|
||||
if media.ID == id {
|
||||
hasMedia = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasMedia {
|
||||
anilist.TestAddAnimeCollectionWithRelationsEntry(animeCollection, id, anilist.TestModifyAnimeCollectionEntryInput{Status: new(anilist.MediaListStatusCurrent)}, anilistClient)
|
||||
allMedia = animeCollection.GetAllAnime()
|
||||
}
|
||||
anilist.EnsureAnimeCollectionWithRelationsEntry(animeCollection, id, anilist.AnimeCollectionEntryPatch{Status: ¤tStatus}, anilistClient)
|
||||
}
|
||||
allMedia := animeCollection.GetAllAnime()
|
||||
|
||||
scanLogger, err := NewConsoleScanLogger()
|
||||
if err != nil {
|
||||
@@ -948,41 +900,27 @@ func TestMatcherWithOfflineDB(t *testing.T) {
|
||||
t.Skip("Skipping integration test")
|
||||
}
|
||||
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
logger := util.NewLogger()
|
||||
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
anilistClientRef := util.NewRef(anilistClient)
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
anilistPlatform := anilist_platform.NewAnilistPlatform(anilistClientRef, extensionBankRef, logger, database)
|
||||
anilistPlatform.SetUsername(cfg.Provider.AnilistUsername)
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
completeAnimeCache := anilist.NewCompleteAnimeCache()
|
||||
anilistRateLimiter := limiter.NewAnilistLimiter()
|
||||
harness := newScannerFixtureHarness(t)
|
||||
logger := harness.Logger
|
||||
|
||||
scanLogger, err := NewConsoleScanLogger()
|
||||
if err != nil {
|
||||
t.Fatal("expected result, got error:", err.Error())
|
||||
}
|
||||
|
||||
dir := "E:/Anime"
|
||||
dir := harness.LibraryDir
|
||||
|
||||
t.Log("Initializing MediaFetcher with anime-offline-database...")
|
||||
|
||||
mf, err := NewMediaFetcher(t.Context(), &MediaFetcherOptions{
|
||||
Enhanced: true,
|
||||
EnhanceWithOfflineDatabase: true, // Use offline database
|
||||
PlatformRef: util.NewRef(anilistPlatform),
|
||||
PlatformRef: util.NewRef[platform.Platform](harness.Platform),
|
||||
LocalFiles: []*anime.LocalFile{}, // Empty, we don't need local files for fetching
|
||||
CompleteAnimeCache: completeAnimeCache,
|
||||
MetadataProviderRef: util.NewRef(metadataProvider),
|
||||
CompleteAnimeCache: harness.CompleteAnimeCache,
|
||||
MetadataProviderRef: util.NewRef(harness.MetadataProvider),
|
||||
Logger: logger,
|
||||
AnilistRateLimiter: anilistRateLimiter,
|
||||
AnilistRateLimiter: harness.AnilistRateLimiter,
|
||||
ScanLogger: scanLogger,
|
||||
DisableAnimeCollection: true, // Only use offline database
|
||||
})
|
||||
@@ -1395,15 +1333,17 @@ func TestGetFileFormatType(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMatcher_applyMatchingRule(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := anilist.NewAnilistClient(cfg.Provider.AnilistJwt, "")
|
||||
animeCollection, err := anilistClient.AnimeCollectionWithRelations(context.Background(), &cfg.Provider.AnilistUsername)
|
||||
harness := newScannerLiveHarness(t)
|
||||
anilistClient := harness.AnilistClient
|
||||
animeCollection, err := harness.Platform.GetAnimeCollectionWithRelations(t.Context())
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
if animeCollection == nil {
|
||||
t.Fatal("expected anime collection, got nil")
|
||||
}
|
||||
|
||||
dir := "E:/Anime"
|
||||
dir := harness.LibraryDir
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -1530,34 +1470,17 @@ func TestMatcher_applyMatchingRule(t *testing.T) {
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
// Add medias to collection if it doesn't exist
|
||||
allMedia := animeCollection.GetAllAnime()
|
||||
expectedIDs := make([]int, len(tt.expectedMediaIds))
|
||||
copy(expectedIDs, tt.expectedMediaIds)
|
||||
|
||||
for _, media := range allMedia {
|
||||
for i, expectedID := range expectedIDs {
|
||||
if media.ID == expectedID {
|
||||
last := len(expectedIDs) - 1
|
||||
expectedIDs[i] = expectedIDs[last]
|
||||
expectedIDs = expectedIDs[:last]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, missingID := range expectedIDs {
|
||||
anilist.TestAddAnimeCollectionWithRelationsEntry(
|
||||
currentStatus := anilist.MediaListStatusCurrent
|
||||
for _, expectedID := range tt.expectedMediaIds {
|
||||
anilist.EnsureAnimeCollectionWithRelationsEntry(
|
||||
animeCollection,
|
||||
missingID,
|
||||
anilist.TestModifyAnimeCollectionEntryInput{
|
||||
Status: new(anilist.MediaListStatusCurrent),
|
||||
},
|
||||
expectedID,
|
||||
anilist.AnimeCollectionEntryPatch{Status: ¤tStatus},
|
||||
anilistClient,
|
||||
)
|
||||
}
|
||||
|
||||
allMedia = animeCollection.GetAllAnime()
|
||||
allMedia := animeCollection.GetAllAnime()
|
||||
|
||||
scanLogger, err := NewConsoleScanLogger()
|
||||
if err != nil {
|
||||
|
||||
@@ -2,12 +2,7 @@ package scanner
|
||||
|
||||
import (
|
||||
"seanime/internal/api/anilist"
|
||||
"seanime/internal/api/metadata_provider"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/library/anime"
|
||||
"seanime/internal/platforms/anilist_platform"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/platforms/platform"
|
||||
"seanime/internal/util"
|
||||
"seanime/internal/util/limiter"
|
||||
"testing"
|
||||
@@ -17,24 +12,10 @@ import (
|
||||
)
|
||||
|
||||
func TestNewMediaFetcher(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
logger := util.NewLogger()
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
anilistClientRef := util.NewRef(anilistClient)
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
anilistPlatform := anilist_platform.NewAnilistPlatform(anilistClientRef, extensionBankRef, logger, database)
|
||||
anilistPlatform.SetUsername(cfg.Provider.AnilistUsername)
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
harness := newScannerFixtureHarness(t)
|
||||
completeAnimeCache := anilist.NewCompleteAnimeCache()
|
||||
anilistRateLimiter := limiter.NewAnilistLimiter()
|
||||
|
||||
dir := "E:/Anime"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
paths []string
|
||||
@@ -78,11 +59,7 @@ func TestNewMediaFetcher(t *testing.T) {
|
||||
// | Local Files |
|
||||
// +---------------------+
|
||||
|
||||
var lfs []*anime.LocalFile
|
||||
for _, path := range tt.paths {
|
||||
lf := anime.NewLocalFile(path, dir)
|
||||
lfs = append(lfs, lf)
|
||||
}
|
||||
lfs := harness.LocalFiles(tt.paths...)
|
||||
|
||||
// +---------------------+
|
||||
// | MediaFetcher |
|
||||
@@ -90,10 +67,10 @@ func TestNewMediaFetcher(t *testing.T) {
|
||||
|
||||
mf, err := NewMediaFetcher(t.Context(), &MediaFetcherOptions{
|
||||
Enhanced: tt.enhanced,
|
||||
PlatformRef: util.NewRef(anilistPlatform),
|
||||
PlatformRef: util.NewRef[platform.Platform](harness.Platform),
|
||||
LocalFiles: lfs,
|
||||
CompleteAnimeCache: completeAnimeCache,
|
||||
MetadataProviderRef: util.NewRef(metadataProvider),
|
||||
MetadataProviderRef: util.NewRef(harness.MetadataProvider),
|
||||
Logger: util.NewLogger(),
|
||||
AnilistRateLimiter: anilistRateLimiter,
|
||||
ScanLogger: scanLogger,
|
||||
@@ -119,23 +96,10 @@ func TestNewMediaFetcher(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewEnhancedMediaFetcher(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
logger := util.NewLogger()
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
anilistClientRef := util.NewRef(anilistClient)
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
anilistPlatform := anilist_platform.NewAnilistPlatform(anilistClientRef, extensionBankRef, logger, database)
|
||||
metaProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
harness := newScannerFixtureHarness(t)
|
||||
completeAnimeCache := anilist.NewCompleteAnimeCache()
|
||||
anilistRateLimiter := limiter.NewAnilistLimiter()
|
||||
|
||||
dir := "E:/Anime"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
paths []string
|
||||
@@ -157,7 +121,7 @@ func TestNewEnhancedMediaFetcher(t *testing.T) {
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
scanLogger, err := NewScanLogger("./logs")
|
||||
scanLogger, err := NewScanLogger(harness.Env.RootPath("logs"))
|
||||
if err != nil {
|
||||
t.Fatal("expected result, got error:", err.Error())
|
||||
}
|
||||
@@ -166,11 +130,7 @@ func TestNewEnhancedMediaFetcher(t *testing.T) {
|
||||
// | Local Files |
|
||||
// +---------------------+
|
||||
|
||||
var lfs []*anime.LocalFile
|
||||
for _, path := range tt.paths {
|
||||
lf := anime.NewLocalFile(path, dir)
|
||||
lfs = append(lfs, lf)
|
||||
}
|
||||
lfs := harness.LocalFiles(tt.paths...)
|
||||
|
||||
// +---------------------+
|
||||
// | MediaFetcher |
|
||||
@@ -178,10 +138,10 @@ func TestNewEnhancedMediaFetcher(t *testing.T) {
|
||||
|
||||
mf, err := NewMediaFetcher(t.Context(), &MediaFetcherOptions{
|
||||
Enhanced: tt.enhanced,
|
||||
PlatformRef: util.NewRef(anilistPlatform),
|
||||
PlatformRef: util.NewRef[platform.Platform](harness.Platform),
|
||||
LocalFiles: lfs,
|
||||
CompleteAnimeCache: completeAnimeCache,
|
||||
MetadataProviderRef: util.NewRef(metaProvider),
|
||||
MetadataProviderRef: util.NewRef(harness.MetadataProvider),
|
||||
Logger: util.NewLogger(),
|
||||
AnilistRateLimiter: anilistRateLimiter,
|
||||
ScanLogger: scanLogger,
|
||||
@@ -206,18 +166,7 @@ func TestNewEnhancedMediaFetcher(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFetchMediaFromLocalFiles(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
logger := util.NewLogger()
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
anilistClientRef := util.NewRef(anilistClient)
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
anilistPlatform := anilist_platform.NewAnilistPlatform(anilistClientRef, extensionBankRef, logger, database)
|
||||
metaProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
harness := newScannerFixtureHarness(t)
|
||||
completeAnimeCache := anilist.NewCompleteAnimeCache()
|
||||
anilistRateLimiter := limiter.NewAnilistLimiter()
|
||||
|
||||
@@ -238,13 +187,11 @@ func TestFetchMediaFromLocalFiles(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
dir := "E:/Anime"
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
scanLogger, err := NewScanLogger("./logs")
|
||||
scanLogger, err := NewScanLogger(harness.Env.RootPath("logs"))
|
||||
if err != nil {
|
||||
t.Fatal("expected result, got error:", err.Error())
|
||||
}
|
||||
@@ -253,11 +200,7 @@ func TestFetchMediaFromLocalFiles(t *testing.T) {
|
||||
// | Local Files |
|
||||
// +---------------------+
|
||||
|
||||
var lfs []*anime.LocalFile
|
||||
for _, path := range tt.paths {
|
||||
lf := anime.NewLocalFile(path, dir)
|
||||
lfs = append(lfs, lf)
|
||||
}
|
||||
lfs := harness.LocalFiles(tt.paths...)
|
||||
|
||||
// +--------------------------+
|
||||
// | FetchMediaFromLocalFiles |
|
||||
@@ -265,10 +208,10 @@ func TestFetchMediaFromLocalFiles(t *testing.T) {
|
||||
|
||||
media, ok := FetchMediaFromLocalFiles(
|
||||
t.Context(),
|
||||
anilistPlatform,
|
||||
harness.Platform,
|
||||
lfs,
|
||||
completeAnimeCache,
|
||||
metaProvider,
|
||||
harness.MetadataProvider,
|
||||
anilistRateLimiter,
|
||||
scanLogger,
|
||||
)
|
||||
|
||||
@@ -3,9 +3,6 @@ package scanner
|
||||
import (
|
||||
"context"
|
||||
"seanime/internal/api/anilist"
|
||||
"seanime/internal/api/metadata_provider"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/util"
|
||||
"seanime/internal/util/limiter"
|
||||
"testing"
|
||||
@@ -16,18 +13,9 @@ import (
|
||||
)
|
||||
|
||||
func TestMediaTreeAnalysis(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
|
||||
anilistRateLimiter := limiter.NewAnilistLimiter()
|
||||
tree := anilist.NewCompleteAnimeRelationTree()
|
||||
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, util.NewLogger())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
harness := newScannerLiveHarness(t)
|
||||
anilistClient := harness.AnilistClient
|
||||
anilistRateLimiter := harness.AnilistRateLimiter
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -64,6 +52,7 @@ func TestMediaTreeAnalysis(t *testing.T) {
|
||||
t.Fatal("expected media, got not found")
|
||||
}
|
||||
media := mediaF.GetMedia()
|
||||
tree := anilist.NewCompleteAnimeRelationTree()
|
||||
|
||||
// +---------------------+
|
||||
// | MediaTree |
|
||||
@@ -87,7 +76,7 @@ func TestMediaTreeAnalysis(t *testing.T) {
|
||||
|
||||
mta, err := NewMediaTreeAnalysis(&MediaTreeAnalysisOptions{
|
||||
tree: tree,
|
||||
metadataProviderRef: util.NewRef(metadataProvider),
|
||||
metadataProviderRef: util.NewRef(harness.MetadataProvider),
|
||||
rateLimiter: limiter.NewLimiter(time.Minute, 25),
|
||||
})
|
||||
if err != nil {
|
||||
@@ -113,17 +102,9 @@ func TestMediaTreeAnalysis(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMediaTreeAnalysis2(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
anilistRateLimiter := limiter.NewAnilistLimiter()
|
||||
tree := anilist.NewCompleteAnimeRelationTree()
|
||||
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, util.NewLogger())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
harness := newScannerLiveHarness(t)
|
||||
anilistClient := harness.AnilistClient
|
||||
anilistRateLimiter := harness.AnilistRateLimiter
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -143,6 +124,7 @@ func TestMediaTreeAnalysis2(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal("expected media, got error:", err.Error())
|
||||
}
|
||||
tree := anilist.NewCompleteAnimeRelationTree()
|
||||
|
||||
// +---------------------+
|
||||
// | MediaTree |
|
||||
@@ -166,7 +148,7 @@ func TestMediaTreeAnalysis2(t *testing.T) {
|
||||
|
||||
mta, err := NewMediaTreeAnalysis(&MediaTreeAnalysisOptions{
|
||||
tree: tree,
|
||||
metadataProviderRef: util.NewRef(metadataProvider),
|
||||
metadataProviderRef: util.NewRef(harness.MetadataProvider),
|
||||
rateLimiter: limiter.NewLimiter(time.Minute, 25),
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -1,38 +1,22 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"seanime/internal/api/anilist"
|
||||
"seanime/internal/api/metadata_provider"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/library/anime"
|
||||
"seanime/internal/platforms/anilist_platform"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/platforms/platform"
|
||||
"seanime/internal/util"
|
||||
"seanime/internal/util/limiter"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestScanLogger(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
logger := util.NewLogger()
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
anilistClientRef := util.NewRef(anilistClient)
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
anilistPlatform := anilist_platform.NewAnilistPlatform(anilistClientRef, extensionBankRef, logger, database)
|
||||
animeCollection, err := anilistPlatform.GetAnimeCollectionWithRelations(t.Context())
|
||||
harness := newScannerFixtureHarness(t)
|
||||
logger := harness.Logger
|
||||
animeCollection, err := harness.Platform.GetAnimeCollectionWithRelations(t.Context())
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
if animeCollection == nil {
|
||||
t.Fatal("expected anime collection, got nil")
|
||||
}
|
||||
allMedia := animeCollection.GetAllAnime()
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
completeAnimeCache := anilist.NewCompleteAnimeCache()
|
||||
anilistRateLimiter := limiter.NewAnilistLimiter()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -55,7 +39,7 @@ func TestScanLogger(t *testing.T) {
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
scanLogger, err := NewScanLogger("./logs")
|
||||
scanLogger, err := NewScanLogger(harness.Env.RootPath("logs"))
|
||||
if err != nil {
|
||||
t.Fatal("expected result, got error:", err.Error())
|
||||
}
|
||||
@@ -64,11 +48,7 @@ func TestScanLogger(t *testing.T) {
|
||||
// | Local Files |
|
||||
// +---------------------+
|
||||
|
||||
var lfs []*anime.LocalFile
|
||||
for _, path := range tt.paths {
|
||||
lf := anime.NewLocalFile(path, "E:/Anime")
|
||||
lfs = append(lfs, lf)
|
||||
}
|
||||
lfs := harness.LocalFiles(tt.paths...)
|
||||
|
||||
// +---------------------+
|
||||
// | MediaContainer |
|
||||
@@ -107,10 +87,10 @@ func TestScanLogger(t *testing.T) {
|
||||
fh := FileHydrator{
|
||||
LocalFiles: lfs,
|
||||
AllMedia: mc.NormalizedMedia,
|
||||
CompleteAnimeCache: completeAnimeCache,
|
||||
PlatformRef: util.NewRef(anilistPlatform),
|
||||
MetadataProviderRef: util.NewRef(metadataProvider),
|
||||
AnilistRateLimiter: anilistRateLimiter,
|
||||
CompleteAnimeCache: harness.CompleteAnimeCache,
|
||||
PlatformRef: util.NewRef[platform.Platform](harness.Platform),
|
||||
MetadataProviderRef: util.NewRef(harness.MetadataProvider),
|
||||
AnilistRateLimiter: harness.AnilistRateLimiter,
|
||||
Logger: logger,
|
||||
ScanLogger: scanLogger,
|
||||
ScanSummaryLogger: nil,
|
||||
|
||||
@@ -3,14 +3,9 @@ package scanner
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"seanime/internal/api/anilist"
|
||||
"seanime/internal/api/metadata_provider"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/events"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/library/anime"
|
||||
"seanime/internal/platforms/anilist_platform"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/platforms/platform"
|
||||
"seanime/internal/util"
|
||||
"testing"
|
||||
|
||||
@@ -18,14 +13,8 @@ import (
|
||||
)
|
||||
|
||||
func TestScanner_Shelving(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
logger := util.NewLogger()
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
harness := newScannerFixtureHarness(t)
|
||||
logger := harness.Logger
|
||||
|
||||
// a temporary directory for the library
|
||||
tempDir, err := os.MkdirTemp("", "seanime_test_library")
|
||||
@@ -42,11 +31,6 @@ func TestScanner_Shelving(t *testing.T) {
|
||||
filename := "[SubsPlease] 86 - Eighty Six - 20v2 (1080p) [30072859].mkv"
|
||||
filePath := filepath.Join(tempDir, filename)
|
||||
|
||||
anilistClientRef := util.NewRef[anilist.AnilistClient](anilistClient)
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
anilistPlatform := anilist_platform.NewAnilistPlatform(anilistClientRef, extensionBankRef, logger, database)
|
||||
anilistPlatform.SetUsername(cfg.Provider.AnilistUsername)
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
wsEventManager := events.NewMockWSEventManager(util.NewLogger())
|
||||
|
||||
t.Run("Shelve missing locked file", func(t *testing.T) {
|
||||
@@ -60,8 +44,8 @@ func TestScanner_Shelving(t *testing.T) {
|
||||
scanner := &Scanner{
|
||||
DirPath: tempDir,
|
||||
Enhanced: false,
|
||||
PlatformRef: util.NewRef(anilistPlatform),
|
||||
MetadataProviderRef: util.NewRef(metadataProvider),
|
||||
PlatformRef: util.NewRef[platform.Platform](harness.Platform),
|
||||
MetadataProviderRef: util.NewRef(harness.MetadataProvider),
|
||||
Logger: logger,
|
||||
WSEventManager: wsEventManager,
|
||||
ExistingLocalFiles: existingLfs,
|
||||
@@ -105,8 +89,8 @@ func TestScanner_Shelving(t *testing.T) {
|
||||
scanner := &Scanner{
|
||||
DirPath: tempDir,
|
||||
Enhanced: false,
|
||||
PlatformRef: util.NewRef(anilistPlatform),
|
||||
MetadataProviderRef: util.NewRef(metadataProvider),
|
||||
PlatformRef: util.NewRef[platform.Platform](harness.Platform),
|
||||
MetadataProviderRef: util.NewRef(harness.MetadataProvider),
|
||||
Logger: logger,
|
||||
WSEventManager: wsEventManager,
|
||||
ExistingLocalFiles: existingLfs,
|
||||
@@ -147,8 +131,8 @@ func TestScanner_Shelving(t *testing.T) {
|
||||
scanner := &Scanner{
|
||||
DirPath: tempDir,
|
||||
Enhanced: false,
|
||||
PlatformRef: util.NewRef(anilistPlatform),
|
||||
MetadataProviderRef: util.NewRef(metadataProvider),
|
||||
PlatformRef: util.NewRef[platform.Platform](harness.Platform),
|
||||
MetadataProviderRef: util.NewRef(harness.MetadataProvider),
|
||||
Logger: logger,
|
||||
WSEventManager: wsEventManager,
|
||||
ExistingLocalFiles: existingLfs,
|
||||
@@ -190,8 +174,8 @@ func TestScanner_Shelving(t *testing.T) {
|
||||
DirPath: tempDir, // The main scan dir is tempDir
|
||||
OtherDirPaths: []string{missingDir}, // We include the missing dir as a library path
|
||||
Enhanced: false,
|
||||
PlatformRef: util.NewRef(anilistPlatform),
|
||||
MetadataProviderRef: util.NewRef(metadataProvider),
|
||||
PlatformRef: util.NewRef[platform.Platform](harness.Platform),
|
||||
MetadataProviderRef: util.NewRef(harness.MetadataProvider),
|
||||
Logger: logger,
|
||||
WSEventManager: wsEventManager,
|
||||
ExistingLocalFiles: existingLfs,
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"seanime/internal/api/anilist"
|
||||
"seanime/internal/api/metadata_provider"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/events"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/library/anime"
|
||||
"seanime/internal/platforms/anilist_platform"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/platforms/platform"
|
||||
"seanime/internal/util"
|
||||
"testing"
|
||||
)
|
||||
@@ -16,20 +11,9 @@ import (
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
func TestScanner_Scan(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
anilistClient := anilist.TestGetMockAnilistClient()
|
||||
logger := util.NewLogger()
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
anilistClientRef := util.NewRef(anilistClient)
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
anilistPlatform := anilist_platform.NewAnilistPlatform(anilistClientRef, extensionBankRef, logger, database)
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, database)
|
||||
harness := newScannerFixtureHarness(t)
|
||||
wsEventManager := events.NewMockWSEventManager(util.NewLogger())
|
||||
dir := "E:/Anime"
|
||||
dir := harness.LibraryDir
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -63,8 +47,8 @@ func TestScanner_Scan(t *testing.T) {
|
||||
scanner := &Scanner{
|
||||
DirPath: dir,
|
||||
Enhanced: false,
|
||||
PlatformRef: util.NewRef(anilistPlatform),
|
||||
MetadataProviderRef: util.NewRef(metadataProvider),
|
||||
PlatformRef: util.NewRef[platform.Platform](harness.Platform),
|
||||
MetadataProviderRef: util.NewRef(harness.MetadataProvider),
|
||||
Logger: util.NewLogger(),
|
||||
WSEventManager: wsEventManager,
|
||||
ExistingLocalFiles: existingLfs,
|
||||
|
||||
85
internal/library/scanner/test_harness_test.go
Normal file
85
internal/library/scanner/test_harness_test.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"seanime/internal/api/anilist"
|
||||
"seanime/internal/api/metadata_provider"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/events"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/library/anime"
|
||||
"seanime/internal/platforms/anilist_platform"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/util"
|
||||
"seanime/internal/util/limiter"
|
||||
"testing"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
const scannerTestLibraryDir = "E:/Anime"
|
||||
|
||||
type scannerTestHarness struct {
|
||||
Env *testutil.TestEnv
|
||||
Config *testutil.Config
|
||||
Logger *zerolog.Logger
|
||||
Database *db.Database
|
||||
AnilistClient anilist.AnilistClient
|
||||
Platform *anilist_platform.AnilistPlatform
|
||||
MetadataProvider metadata_provider.Provider
|
||||
CompleteAnimeCache *anilist.CompleteAnimeCache
|
||||
AnilistRateLimiter *limiter.Limiter
|
||||
WSEventManager events.WSEventManagerInterface
|
||||
LibraryDir string
|
||||
}
|
||||
|
||||
func newScannerFixtureHarness(t testing.TB) *scannerTestHarness {
|
||||
t.Helper()
|
||||
|
||||
env := testutil.NewTestEnv(t)
|
||||
return newScannerHarness(t, env, anilist.NewTestAnilistClient(), "")
|
||||
}
|
||||
|
||||
func newScannerLiveHarness(t testing.TB) *scannerTestHarness {
|
||||
t.Helper()
|
||||
|
||||
env := testutil.NewTestEnv(t, testutil.Anilist())
|
||||
cfg := env.Config()
|
||||
|
||||
return newScannerHarness(t, env, anilist.NewAnilistClient(cfg.Provider.AnilistJwt, ""), cfg.Provider.AnilistUsername)
|
||||
}
|
||||
|
||||
func newScannerHarness(t testing.TB, env *testutil.TestEnv, client anilist.AnilistClient, username string) *scannerTestHarness {
|
||||
t.Helper()
|
||||
|
||||
logger := env.Logger()
|
||||
database := env.MustNewDatabase(logger)
|
||||
anilistClientRef := util.NewRef(client)
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
platform := anilist_platform.NewAnilistPlatform(anilistClientRef, extensionBankRef, logger, database).(*anilist_platform.AnilistPlatform)
|
||||
if username != "" {
|
||||
platform.SetUsername(username)
|
||||
}
|
||||
|
||||
return &scannerTestHarness{
|
||||
Env: env,
|
||||
Config: env.Config(),
|
||||
Logger: logger,
|
||||
Database: database,
|
||||
AnilistClient: client,
|
||||
Platform: platform,
|
||||
MetadataProvider: metadata_provider.NewTestProviderWithEnv(env, database),
|
||||
CompleteAnimeCache: anilist.NewCompleteAnimeCache(),
|
||||
AnilistRateLimiter: limiter.NewAnilistLimiter(),
|
||||
WSEventManager: events.NewMockWSEventManager(logger),
|
||||
LibraryDir: scannerTestLibraryDir,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *scannerTestHarness) LocalFiles(paths ...string) []*anime.LocalFile {
|
||||
localFiles := make([]*anime.LocalFile, 0, len(paths))
|
||||
for _, path := range paths {
|
||||
localFiles = append(localFiles, anime.NewLocalFile(path, h.LibraryDir))
|
||||
}
|
||||
|
||||
return localFiles
|
||||
}
|
||||
@@ -369,7 +369,7 @@ func (m *ManagerImpl) TrackAnime(mId int) error {
|
||||
|
||||
err := m.localDb.gormdb.Create(s).Error
|
||||
if err != nil {
|
||||
m.logger.Error().Msgf("local manager: Failed to add anime %d to local database: %w", mId, err)
|
||||
m.logger.Error().Err(err).Msgf("local manager: Failed to add anime %d to local database", mId)
|
||||
return fmt.Errorf("failed to add anime %d to local database: %w", mId, err)
|
||||
}
|
||||
|
||||
@@ -426,7 +426,7 @@ func (m *ManagerImpl) TrackManga(mId int) error {
|
||||
|
||||
err := m.localDb.gormdb.Create(s).Error
|
||||
if err != nil {
|
||||
m.logger.Error().Msgf("local manager: Failed to add manga %d to local database: %w", mId, err)
|
||||
m.logger.Error().Err(err).Msgf("local manager: Failed to add manga %d to local database", mId)
|
||||
return fmt.Errorf("failed to add manga %d to local database: %w", mId, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -684,7 +684,6 @@ func (q *Syncer) synchronizeAnime(diff *AnimeDiffResult) {
|
||||
}
|
||||
|
||||
// The snapshot is up-to-date
|
||||
return
|
||||
}
|
||||
|
||||
// synchronizeManga creates or updates the manga snapshot in the local database.
|
||||
@@ -775,5 +774,4 @@ func (q *Syncer) synchronizeManga(diff *MangaDiffResult) {
|
||||
}
|
||||
|
||||
// The snapshot is up-to-date
|
||||
return
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"seanime/internal/api/anilist"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/platforms/anilist_platform"
|
||||
"seanime/internal/testutil"
|
||||
@@ -16,22 +15,19 @@ import (
|
||||
)
|
||||
|
||||
func testSetupManager(t *testing.T) (Manager, *anilist.AnimeCollection, *anilist.MangaCollection) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.Anilist())
|
||||
env := testutil.NewTestEnv(t)
|
||||
logger := env.Logger()
|
||||
|
||||
logger := util.NewLogger()
|
||||
|
||||
database, err := db.NewDatabase(cfg.Path.DataDir, cfg.Database.Name, logger)
|
||||
require.NoError(t, err)
|
||||
anilistClient := anilist.NewAnilistClient(cfg.Provider.AnilistJwt, "")
|
||||
database := env.MustNewDatabase(logger)
|
||||
anilistClient := anilist.NewTestAnilistClient()
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
anilistPlatform := anilist_platform.NewAnilistPlatform(util.NewRef[anilist.AnilistClient](anilistClient), extensionBankRef, logger, database)
|
||||
anilistPlatform.SetUsername(cfg.Provider.AnilistUsername)
|
||||
animeCollection, err := anilistPlatform.GetAnimeCollection(t.Context(), true)
|
||||
require.NoError(t, err)
|
||||
mangaCollection, err := anilistPlatform.GetMangaCollection(t.Context(), true)
|
||||
require.NoError(t, err)
|
||||
|
||||
manager := GetMockManager(t, database)
|
||||
manager := NewTestManager(t, database)
|
||||
|
||||
manager.SetAnimeCollection(animeCollection)
|
||||
manager.SetMangaCollection(mangaCollection)
|
||||
@@ -72,7 +68,7 @@ func TestSync2(t *testing.T) {
|
||||
break
|
||||
}
|
||||
|
||||
anilist.TestModifyAnimeCollectionEntry(animeCollection, 130003, anilist.TestModifyAnimeCollectionEntryInput{
|
||||
anilist.PatchAnimeCollectionEntry(animeCollection, 130003, anilist.AnimeCollectionEntryPatch{
|
||||
Status: new(anilist.MediaListStatusCompleted),
|
||||
Progress: new(12), // Mock progress
|
||||
})
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package local
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"seanime/internal/api/anilist"
|
||||
"seanime/internal/api/metadata_provider"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/database/db_bridge"
|
||||
"seanime/internal/database/models"
|
||||
"seanime/internal/events"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/library/anime"
|
||||
"seanime/internal/manga"
|
||||
"seanime/internal/platforms/anilist_platform"
|
||||
"seanime/internal/platforms/platform"
|
||||
@@ -17,28 +19,36 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func GetMockManager(t *testing.T, db *db.Database) Manager {
|
||||
cfg := testutil.LoadConfig(t)
|
||||
func NewTestManager(t *testing.T, db *db.Database) Manager {
|
||||
env := testutil.NewTestEnv(t)
|
||||
|
||||
logger := util.NewLogger()
|
||||
metadataProvider := metadata_provider.GetFakeProvider(t, db)
|
||||
metadataProviderRef := util.NewRef[metadata_provider.Provider](metadataProvider)
|
||||
mangaRepository := manga.GetFakeRepository(t, db)
|
||||
logger := env.Logger()
|
||||
metadataProvider := metadata_provider.NewTestProviderWithEnv(env, db)
|
||||
metadataProviderRef := util.NewRef(metadataProvider)
|
||||
mangaRepository := manga.NewTestRepositoryWithEnv(env, db)
|
||||
|
||||
wsEventManager := events.NewMockWSEventManager(logger)
|
||||
anilistClient := anilist.NewMockAnilistClient()
|
||||
anilistClient := anilist.NewFixtureAnilistClient()
|
||||
anilistClientRef := util.NewRef[anilist.AnilistClient](anilistClient)
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
anilistPlatform := anilist_platform.NewAnilistPlatform(anilistClientRef, extensionBankRef, logger, db)
|
||||
anilistPlatformRef := util.NewRef[platform.Platform](anilistPlatform)
|
||||
|
||||
localDir := filepath.Join(cfg.Path.DataDir, "offline")
|
||||
assetsDir := filepath.Join(cfg.Path.DataDir, "offline", "assets")
|
||||
localDir := env.MustMkdirData("offline")
|
||||
assetsDir := env.MustMkdirData("offline", "assets")
|
||||
|
||||
var localFilesCount int64
|
||||
err := db.Gorm().Model(&models.LocalFiles{}).Count(&localFilesCount).Error
|
||||
require.NoError(t, err)
|
||||
if localFilesCount == 0 {
|
||||
_, err = db_bridge.InsertLocalFiles(db, make([]*anime.LocalFile, 0))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
m, err := NewManager(&NewManagerOptions{
|
||||
LocalDir: localDir,
|
||||
AssetDir: assetsDir,
|
||||
Logger: util.NewLogger(),
|
||||
Logger: logger,
|
||||
MetadataProviderRef: metadataProviderRef,
|
||||
MangaRepository: mangaRepository,
|
||||
Database: db,
|
||||
@@ -1,29 +1,32 @@
|
||||
package chapter_downloader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/events"
|
||||
hibikemanga "seanime/internal/extension/hibike/manga"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/util"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/goccy/go-json"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestQueue(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t)
|
||||
func newTestDownloader(t *testing.T) (*Downloader, *db.Database, string) {
|
||||
t.Helper()
|
||||
|
||||
tempDir := t.TempDir()
|
||||
|
||||
logger := util.NewLogger()
|
||||
database, err := db.NewDatabase(tempDir, cfg.Database.Name, logger)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create database: %v", err)
|
||||
}
|
||||
|
||||
downloadDir := t.TempDir()
|
||||
env := testutil.NewTestEnv(t)
|
||||
logger := env.Logger()
|
||||
database := env.MustNewDatabase(logger)
|
||||
downloadDir := env.MustMkdir("downloads")
|
||||
|
||||
downloader := NewDownloader(&NewDownloaderOptions{
|
||||
Logger: logger,
|
||||
@@ -32,81 +35,107 @@ func TestQueue(t *testing.T) {
|
||||
DownloadDir: downloadDir,
|
||||
})
|
||||
|
||||
downloader.Start()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
providerName string
|
||||
provider hibikemanga.Provider
|
||||
mangaId string
|
||||
mediaId int
|
||||
chapterIndex uint
|
||||
}{
|
||||
{
|
||||
//providerName: manga_providers.REPLACE,
|
||||
//provider: manga_providers.REPLACE(util.NewLogger()),
|
||||
//name: "Jujutsu Kaisen",
|
||||
//mangaId: "TA22I5O7",
|
||||
//chapterIndex: 258,
|
||||
//mediaId: 101517,
|
||||
},
|
||||
{
|
||||
//providerName: manga_providers.REPLACE,
|
||||
//provider: manga_providers.REPLACE(util.NewLogger()),
|
||||
//name: "Jujutsu Kaisen",
|
||||
//mangaId: "TA22I5O7",
|
||||
//chapterIndex: 259,
|
||||
//mediaId: 101517,
|
||||
},
|
||||
return downloader, database, downloadDir
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
func newTestPNG(t *testing.T) []byte {
|
||||
t.Helper()
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
img := image.NewRGBA(image.Rect(0, 0, 1, 1))
|
||||
img.Set(0, 0, color.RGBA{R: 255, G: 128, B: 64, A: 255})
|
||||
require.NoError(t, png.Encode(&buf, img))
|
||||
|
||||
// SETUP
|
||||
chapters, err := tt.provider.FindChapters(tt.mangaId)
|
||||
if assert.NoError(t, err, "comick.FindChapters() error") {
|
||||
|
||||
assert.NotEmpty(t, chapters, "chapters is empty")
|
||||
|
||||
var chapterInfo *hibikemanga.ChapterDetails
|
||||
for _, chapter := range chapters {
|
||||
if chapter.Index == tt.chapterIndex {
|
||||
chapterInfo = chapter
|
||||
break
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
if assert.NotNil(t, chapterInfo, "chapter not found") {
|
||||
pages, err := tt.provider.FindChapterPages(chapterInfo.ID)
|
||||
if assert.NoError(t, err, "provider.FindChapterPages() error") {
|
||||
assert.NotEmpty(t, pages, "pages is empty")
|
||||
func TestQueueAddsItemToDatabase(t *testing.T) {
|
||||
downloader, database, _ := newTestDownloader(t)
|
||||
|
||||
pages := []*hibikemanga.ChapterPage{{
|
||||
Index: 0,
|
||||
URL: "https://example.com/01.png",
|
||||
}}
|
||||
id := DownloadID{
|
||||
Provider: "test-provider",
|
||||
MediaId: 101517,
|
||||
ChapterId: "chapter-1",
|
||||
ChapterNumber: "1",
|
||||
}
|
||||
|
||||
//
|
||||
// TEST
|
||||
//
|
||||
err := downloader.AddToQueue(DownloadOptions{
|
||||
DownloadID: DownloadID{
|
||||
Provider: string(tt.providerName),
|
||||
MediaId: tt.mediaId,
|
||||
ChapterId: chapterInfo.ID,
|
||||
ChapterNumber: chapterInfo.Chapter,
|
||||
},
|
||||
DownloadID: id,
|
||||
Pages: pages,
|
||||
StartNow: true,
|
||||
StartNow: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to download chapter: %v", err)
|
||||
require.NoError(t, err)
|
||||
|
||||
next, err := database.GetNextChapterDownloadQueueItem()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, next)
|
||||
require.Equal(t, id.Provider, next.Provider)
|
||||
require.Equal(t, id.MediaId, next.MediaID)
|
||||
require.Equal(t, id.ChapterId, next.ChapterID)
|
||||
require.Equal(t, id.ChapterNumber, next.ChapterNumber)
|
||||
require.Equal(t, string(QueueStatusNotStarted), next.Status)
|
||||
require.NotEmpty(t, next.PageData)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
func TestDownloadChapterImagesWritesRegistry(t *testing.T) {
|
||||
downloader, database, downloadDir := newTestDownloader(t)
|
||||
|
||||
imageData := newTestPNG(t)
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "image/png")
|
||||
_, _ = w.Write(imageData)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
pages := []*hibikemanga.ChapterPage{{
|
||||
Index: 0,
|
||||
URL: server.URL + "/page.png",
|
||||
}}
|
||||
id := DownloadID{
|
||||
Provider: "test-provider",
|
||||
MediaId: 101517,
|
||||
ChapterId: "chapter-1",
|
||||
ChapterNumber: "1",
|
||||
}
|
||||
|
||||
err := downloader.AddToQueue(DownloadOptions{
|
||||
DownloadID: id,
|
||||
Pages: pages,
|
||||
StartNow: false,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, database.UpdateChapterDownloadQueueItemStatus(id.Provider, id.MediaId, id.ChapterId, string(QueueStatusDownloading)))
|
||||
downloader.queue.current = &QueueInfo{
|
||||
DownloadID: id,
|
||||
Pages: pages,
|
||||
Status: QueueStatusDownloading,
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Second)
|
||||
err = downloader.downloadChapterImages(downloader.queue.current)
|
||||
require.NoError(t, err)
|
||||
|
||||
chapterDir := filepath.Join(downloadDir, FormatChapterDirName(id.Provider, id.MediaId, id.ChapterId, id.ChapterNumber))
|
||||
registryPath := filepath.Join(chapterDir, "registry.json")
|
||||
registryBytes, err := os.ReadFile(registryPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
var registry Registry
|
||||
require.NoError(t, json.Unmarshal(registryBytes, ®istry))
|
||||
require.Len(t, registry, 1)
|
||||
pageInfo, ok := registry[0]
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "01.png", pageInfo.Filename)
|
||||
require.Equal(t, server.URL+"/page.png", pageInfo.OriginalURL)
|
||||
|
||||
_, err = os.Stat(filepath.Join(chapterDir, pageInfo.Filename))
|
||||
require.NoError(t, err)
|
||||
|
||||
queueItems, err := database.GetChapterDownloadQueue()
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, queueItems)
|
||||
}
|
||||
|
||||
@@ -1,33 +1,32 @@
|
||||
package manga
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/events"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/testutil"
|
||||
"seanime/internal/util"
|
||||
"seanime/internal/util/filecache"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func GetFakeRepository(t *testing.T, db *db.Database) *Repository {
|
||||
cfg := testutil.LoadConfig(t)
|
||||
func NewTestRepository(t *testing.T, db *db.Database) *Repository {
|
||||
t.Helper()
|
||||
|
||||
logger := util.NewLogger()
|
||||
cacheDir := filepath.Join(cfg.Path.DataDir, "cache")
|
||||
fileCacher, err := filecache.NewCacher(cacheDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return NewTestRepositoryWithEnv(testutil.NewTestEnv(t), db)
|
||||
}
|
||||
|
||||
func NewTestRepositoryWithEnv(env *testutil.TestEnv, db *db.Database) *Repository {
|
||||
logger := env.Logger()
|
||||
cacheDir := env.EnsureCacheDir()
|
||||
fileCacher := env.NewCacher()
|
||||
|
||||
repository := NewRepository(&NewRepositoryOptions{
|
||||
Logger: logger,
|
||||
FileCacher: fileCacher,
|
||||
CacheDir: cacheDir,
|
||||
ServerURI: "",
|
||||
WsEventManager: events.NewMockWSEventManager(logger),
|
||||
DownloadDir: filepath.Join(cfg.Path.DataDir, "manga"),
|
||||
DownloadDir: env.MustMkdirData("manga"),
|
||||
Database: db,
|
||||
ExtensionBankRef: util.NewRef(extension.NewUnifiedBank()),
|
||||
})
|
||||
@@ -27,6 +27,7 @@ func TestMpcHc_Start(t *testing.T) {
|
||||
|
||||
func TestMpcHc_Play(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.MediaPlayer())
|
||||
sampleVideoPath := testutil.RequireSampleVideoPath(t)
|
||||
|
||||
mpc := &MpcHc{
|
||||
Host: cfg.Provider.MpcHost,
|
||||
@@ -38,7 +39,7 @@ func TestMpcHc_Play(t *testing.T) {
|
||||
err := mpc.Start()
|
||||
assert.NoError(t, err)
|
||||
|
||||
res, err := mpc.OpenAndPlay("E:\\ANIME\\Violet.Evergarden.The.Movie.1080p.Dual.Audio.BDRip.10.bits.DD.x265-EMBER.mkv")
|
||||
res, err := mpc.OpenAndPlay(sampleVideoPath)
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Log(res)
|
||||
@@ -69,6 +70,7 @@ func TestMpcHc_GetVariables(t *testing.T) {
|
||||
|
||||
func TestMpcHc_Seek(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t, testutil.MediaPlayer())
|
||||
sampleVideoPath := testutil.RequireSampleVideoPath(t)
|
||||
|
||||
mpc := &MpcHc{
|
||||
Host: cfg.Provider.MpcHost,
|
||||
@@ -80,7 +82,7 @@ func TestMpcHc_Seek(t *testing.T) {
|
||||
err := mpc.Start()
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = mpc.OpenAndPlay("E:\\ANIME\\[SubsPlease] Bocchi the Rock! (01-12) (1080p) [Batch]\\[SubsPlease] Bocchi the Rock! - 01v2 (1080p) [ABDDAE16].mkv")
|
||||
_, err = mpc.OpenAndPlay(sampleVideoPath)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = mpc.Pause()
|
||||
|
||||
@@ -24,6 +24,7 @@ type (
|
||||
logger *zerolog.Logger
|
||||
username mo.Option[string]
|
||||
anilistClient anilist.AnilistClient
|
||||
useFixtureCollections bool
|
||||
animeCollection mo.Option[*anilist.AnimeCollection]
|
||||
rawAnimeCollection mo.Option[*anilist.AnimeCollection]
|
||||
mangaCollection mo.Option[*anilist.MangaCollection]
|
||||
@@ -37,10 +38,13 @@ type (
|
||||
)
|
||||
|
||||
func NewAnilistPlatform(anilistClientRef *util.Ref[anilist.AnilistClient], extensionBankRef *util.Ref[*extension.UnifiedBank], logger *zerolog.Logger, db *db.Database, logoutFunc ...func()) platform.Platform {
|
||||
_, useFixtureCollections := anilistClientRef.Get().(*anilist.FixtureAnilistClient)
|
||||
|
||||
ap := &AnilistPlatform{
|
||||
anilistClient: shared_platform.NewCacheLayer(anilistClientRef, logoutFunc...),
|
||||
logger: logger,
|
||||
username: mo.None[string](),
|
||||
useFixtureCollections: useFixtureCollections,
|
||||
animeCollection: mo.None[*anilist.AnimeCollection](),
|
||||
rawAnimeCollection: mo.None[*anilist.AnimeCollection](),
|
||||
mangaCollection: mo.None[*anilist.MangaCollection](),
|
||||
@@ -76,6 +80,17 @@ func (ap *AnilistPlatform) SetAnilistClient(client anilist.AnilistClient) {
|
||||
ap.anilistClient = client
|
||||
}
|
||||
|
||||
func (ap *AnilistPlatform) getUsername() (*string, bool) {
|
||||
if ap.username.IsPresent() {
|
||||
return ap.username.ToPointer(), true
|
||||
}
|
||||
if ap.useFixtureCollections {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (ap *AnilistPlatform) UpdateEntry(ctx context.Context, mediaID int, status *anilist.MediaListStatus, scoreRaw *int, progress *int, startedAt *anilist.FuzzyDateInput, completedAt *anilist.FuzzyDateInput) error {
|
||||
ap.logger.Trace().Msg("anilist platform: Updating entry")
|
||||
|
||||
@@ -337,7 +352,7 @@ func (ap *AnilistPlatform) GetAnimeCollection(ctx context.Context, bypassCache b
|
||||
return event.AnimeCollection, nil
|
||||
}
|
||||
|
||||
if ap.username.IsAbsent() {
|
||||
if _, ok := ap.getUsername(); !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -368,7 +383,7 @@ func (ap *AnilistPlatform) GetRawAnimeCollection(ctx context.Context, bypassCach
|
||||
return event.AnimeCollection, nil
|
||||
}
|
||||
|
||||
if ap.username.IsAbsent() {
|
||||
if _, ok := ap.getUsername(); !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -389,7 +404,7 @@ func (ap *AnilistPlatform) GetRawAnimeCollection(ctx context.Context, bypassCach
|
||||
}
|
||||
|
||||
func (ap *AnilistPlatform) RefreshAnimeCollection(ctx context.Context) (*anilist.AnimeCollection, error) {
|
||||
if ap.username.IsAbsent() {
|
||||
if _, ok := ap.getUsername(); !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -418,12 +433,13 @@ func (ap *AnilistPlatform) RefreshAnimeCollection(ctx context.Context) (*anilist
|
||||
}
|
||||
|
||||
func (ap *AnilistPlatform) refreshAnimeCollection(ctx context.Context) error {
|
||||
if ap.username.IsAbsent() {
|
||||
userName, ok := ap.getUsername()
|
||||
if !ok {
|
||||
return errors.New("anilist: Username is not set")
|
||||
}
|
||||
|
||||
// Else, get the collection from Anilist
|
||||
collection, err := ap.anilistClient.AnimeCollection(ctx, ap.username.ToPointer())
|
||||
collection, err := ap.anilistClient.AnimeCollection(ctx, userName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -450,11 +466,12 @@ func (ap *AnilistPlatform) refreshAnimeCollection(ctx context.Context) error {
|
||||
func (ap *AnilistPlatform) GetAnimeCollectionWithRelations(ctx context.Context) (*anilist.AnimeCollectionWithRelations, error) {
|
||||
ap.logger.Trace().Msg("anilist platform: Fetching anime collection with relations")
|
||||
|
||||
if ap.username.IsAbsent() {
|
||||
userName, ok := ap.getUsername()
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ret, err := ap.anilistClient.AnimeCollectionWithRelations(ctx, ap.username.ToPointer())
|
||||
ret, err := ap.anilistClient.AnimeCollectionWithRelations(ctx, userName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -474,7 +491,7 @@ func (ap *AnilistPlatform) GetMangaCollection(ctx context.Context, bypassCache b
|
||||
return event.MangaCollection, nil
|
||||
}
|
||||
|
||||
if ap.username.IsAbsent() {
|
||||
if _, ok := ap.getUsername(); !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -508,7 +525,7 @@ func (ap *AnilistPlatform) GetRawMangaCollection(ctx context.Context, bypassCach
|
||||
return event.MangaCollection, nil
|
||||
}
|
||||
|
||||
if ap.username.IsAbsent() {
|
||||
if _, ok := ap.getUsername(); !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -529,7 +546,7 @@ func (ap *AnilistPlatform) GetRawMangaCollection(ctx context.Context, bypassCach
|
||||
}
|
||||
|
||||
func (ap *AnilistPlatform) RefreshMangaCollection(ctx context.Context) (*anilist.MangaCollection, error) {
|
||||
if ap.username.IsAbsent() {
|
||||
if _, ok := ap.getUsername(); !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -558,11 +575,12 @@ func (ap *AnilistPlatform) RefreshMangaCollection(ctx context.Context) (*anilist
|
||||
}
|
||||
|
||||
func (ap *AnilistPlatform) refreshMangaCollection(ctx context.Context) error {
|
||||
if ap.username.IsAbsent() {
|
||||
userName, ok := ap.getUsername()
|
||||
if !ok {
|
||||
return errors.New("anilist: Username is not set")
|
||||
}
|
||||
|
||||
collection, err := ap.anilistClient.MangaCollection(ctx, ap.username.ToPointer())
|
||||
collection, err := ap.anilistClient.MangaCollection(ctx, userName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
@@ -58,12 +59,21 @@ type ProviderConfig struct {
|
||||
|
||||
type PathConfig struct {
|
||||
DataDir string `mapstructure:"dataDir"`
|
||||
SampleVideoPath string `mapstructure:"sampleVideoPath"`
|
||||
}
|
||||
|
||||
type DatabaseConfig struct {
|
||||
Name string `mapstructure:"name"`
|
||||
}
|
||||
|
||||
func defaultConfig() *Config {
|
||||
return &Config{
|
||||
Path: PathConfig{},
|
||||
Database: DatabaseConfig{Name: defaultTestDatabaseName},
|
||||
Flags: FlagsConfig{},
|
||||
}
|
||||
}
|
||||
|
||||
// SkipFunc conditionally skips a test based on configuration.
|
||||
type SkipFunc func(t testing.TB, cfg *Config)
|
||||
|
||||
@@ -115,12 +125,20 @@ func TestDataPath(name string) string {
|
||||
return filepath.Join(ProjectRoot(), "test", "testdata", name+".json")
|
||||
}
|
||||
|
||||
const (
|
||||
SampleVideoPathEnv = "TEST_SAMPLE_VIDEO_PATH"
|
||||
RecordAnilistFixturesEnvName = "SEANIME_TEST_RECORD_ANILIST_FIXTURES"
|
||||
)
|
||||
|
||||
// InitTestProvider loads the test configuration and skips the test
|
||||
// if any of the provided skip functions decide it should not run.
|
||||
func InitTestProvider(t testing.TB, flags ...SkipFunc) *Config {
|
||||
t.Helper()
|
||||
|
||||
cfg := LoadConfig(t)
|
||||
cfg, err := readConfig()
|
||||
if err != nil {
|
||||
cfg = defaultConfig()
|
||||
}
|
||||
|
||||
for _, fn := range flags {
|
||||
fn(t, cfg)
|
||||
@@ -166,6 +184,47 @@ func readConfig() (*Config, error) {
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
func cloneConfig(cfg *Config) *Config {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return new(*cfg)
|
||||
}
|
||||
|
||||
// RequireSampleVideoPath returns the configured sample media path for external
|
||||
// playback tests. It respects TEST_SAMPLE_VIDEO_PATH and skips if unset.
|
||||
func RequireSampleVideoPath(t testing.TB) string {
|
||||
t.Helper()
|
||||
|
||||
if path := os.Getenv(SampleVideoPathEnv); path != "" {
|
||||
return path
|
||||
}
|
||||
|
||||
cfg := LoadConfig(t)
|
||||
if cfg.Path.SampleVideoPath == "" {
|
||||
t.Skip("media playback tests require path.sampleVideoPath or TEST_SAMPLE_VIDEO_PATH")
|
||||
}
|
||||
|
||||
return cfg.Path.SampleVideoPath
|
||||
}
|
||||
|
||||
// ShouldRecordAnilistFixtures reports whether AniList mock helpers may write
|
||||
// back into repository fixtures during a test run.
|
||||
func ShouldRecordAnilistFixtures() bool {
|
||||
value := os.Getenv(RecordAnilistFixturesEnvName)
|
||||
if value == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
enabled, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return enabled
|
||||
}
|
||||
|
||||
func Anilist() SkipFunc {
|
||||
return func(t testing.TB, cfg *Config) {
|
||||
t.Helper()
|
||||
|
||||
@@ -21,3 +21,14 @@ func TestLoadConfig_IsolatedInstances(t *testing.T) {
|
||||
first.Path.DataDir = t.TempDir()
|
||||
assert.NotEqual(t, first.Path.DataDir, second.Path.DataDir)
|
||||
}
|
||||
|
||||
func TestInitTestProvider_DefaultsWithoutConfig(t *testing.T) {
|
||||
t.Setenv("TEST_CONFIG_PATH", t.TempDir())
|
||||
|
||||
cfg := InitTestProvider(t)
|
||||
|
||||
assert.NotNil(t, cfg)
|
||||
assert.Equal(t, defaultTestDatabaseName, cfg.Database.Name)
|
||||
assert.Empty(t, cfg.Path.DataDir)
|
||||
assert.False(t, cfg.Flags.EnableAnilistTests)
|
||||
}
|
||||
|
||||
217
internal/testutil/env.go
Normal file
217
internal/testutil/env.go
Normal file
@@ -0,0 +1,217 @@
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
pathpkg "path"
|
||||
"path/filepath"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/util"
|
||||
"seanime/internal/util/filecache"
|
||||
"strings"
|
||||
"testing"
|
||||
"unicode"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
const defaultTestDatabaseName = "seanime-test"
|
||||
|
||||
type TestEnv struct {
|
||||
t testing.TB
|
||||
RootDir string
|
||||
DataDir string
|
||||
CacheDir string
|
||||
logger *zerolog.Logger
|
||||
cfg *Config
|
||||
}
|
||||
|
||||
func NewTestEnv(t testing.TB, flags ...SkipFunc) *TestEnv {
|
||||
t.Helper()
|
||||
|
||||
cfg, err := readConfig()
|
||||
if err != nil {
|
||||
if len(flags) > 0 {
|
||||
t.Skipf("testutil: skipping flagged test env because test config is unavailable: %v", err)
|
||||
}
|
||||
cfg = defaultConfig()
|
||||
}
|
||||
for _, fn := range flags {
|
||||
fn(t, cfg)
|
||||
}
|
||||
|
||||
rootDir := t.TempDir()
|
||||
dataDir := filepath.Join(rootDir, "data")
|
||||
env := &TestEnv{
|
||||
t: t,
|
||||
RootDir: rootDir,
|
||||
DataDir: dataDir,
|
||||
CacheDir: filepath.Join(dataDir, "cache"),
|
||||
logger: util.NewLogger(),
|
||||
cfg: cloneConfig(cfg),
|
||||
}
|
||||
|
||||
env.cfg.Path.DataDir = env.DataDir
|
||||
env.cfg.Database.Name = sanitizeTestName(t.Name())
|
||||
|
||||
env.mustMkdirAll(env.DataDir)
|
||||
env.mustMkdirAll(env.CacheDir)
|
||||
|
||||
return env
|
||||
}
|
||||
|
||||
func (env *TestEnv) Logger() *zerolog.Logger {
|
||||
return env.logger
|
||||
}
|
||||
|
||||
func (env *TestEnv) Config() *Config {
|
||||
return cloneConfig(env.cfg)
|
||||
}
|
||||
|
||||
func (env *TestEnv) RootPath(parts ...string) string {
|
||||
return filepath.Join(append([]string{env.RootDir}, parts...)...)
|
||||
}
|
||||
|
||||
func (env *TestEnv) DataPath(parts ...string) string {
|
||||
return filepath.Join(append([]string{env.DataDir}, parts...)...)
|
||||
}
|
||||
|
||||
func (env *TestEnv) CachePath(parts ...string) string {
|
||||
return filepath.Join(append([]string{env.CacheDir}, parts...)...)
|
||||
}
|
||||
|
||||
func (env *TestEnv) EnsureDir(parts ...string) string {
|
||||
return env.mustMkdirAll(env.RootPath(parts...))
|
||||
}
|
||||
|
||||
func (env *TestEnv) EnsureDataDir(parts ...string) string {
|
||||
return env.mustMkdirAll(env.DataPath(parts...))
|
||||
}
|
||||
|
||||
func (env *TestEnv) EnsureCacheDir(parts ...string) string {
|
||||
return env.mustMkdirAll(env.CachePath(parts...))
|
||||
}
|
||||
|
||||
func (env *TestEnv) MustMkdir(parts ...string) string {
|
||||
return env.EnsureDir(parts...)
|
||||
}
|
||||
|
||||
func (env *TestEnv) MustMkdirData(parts ...string) string {
|
||||
return env.EnsureDataDir(parts...)
|
||||
}
|
||||
|
||||
func (env *TestEnv) FixturePath(path string) string {
|
||||
return filepath.Join(env.RootDir, FixtureRelPath(path))
|
||||
}
|
||||
|
||||
func (env *TestEnv) MustWriteFixtureFile(path string, data []byte) string {
|
||||
env.t.Helper()
|
||||
|
||||
target := env.FixturePath(path)
|
||||
env.mustMkdirAll(filepath.Dir(target))
|
||||
if err := os.WriteFile(target, data, 0644); err != nil {
|
||||
env.t.Fatalf("testutil: could not write fixture file %q: %v", target, err)
|
||||
}
|
||||
|
||||
return target
|
||||
}
|
||||
|
||||
func (env *TestEnv) NewCacher(parts ...string) *filecache.Cacher {
|
||||
env.t.Helper()
|
||||
|
||||
dir := env.CachePath(parts...)
|
||||
env.mustMkdirAll(dir)
|
||||
|
||||
cacher, err := filecache.NewCacher(dir)
|
||||
if err != nil {
|
||||
env.t.Fatalf("testutil: could not create cacher: %v", err)
|
||||
}
|
||||
|
||||
return cacher
|
||||
}
|
||||
|
||||
func (env *TestEnv) NewDatabase(name string) *db.Database {
|
||||
env.t.Helper()
|
||||
|
||||
if name == "" {
|
||||
name = env.cfg.Database.Name
|
||||
if name == "" {
|
||||
name = defaultTestDatabaseName
|
||||
}
|
||||
}
|
||||
|
||||
database, err := db.NewDatabase(env.DataDir, name, env.logger)
|
||||
if err != nil {
|
||||
env.t.Fatalf("testutil: could not create database: %v", err)
|
||||
}
|
||||
|
||||
return database
|
||||
}
|
||||
|
||||
func (env *TestEnv) MustNewDatabase(logger *zerolog.Logger) *db.Database {
|
||||
env.t.Helper()
|
||||
|
||||
if logger != nil {
|
||||
env.logger = logger
|
||||
}
|
||||
|
||||
return env.NewDatabase("")
|
||||
}
|
||||
|
||||
func (env *TestEnv) mustMkdirAll(path string) string {
|
||||
env.t.Helper()
|
||||
|
||||
if err := os.MkdirAll(path, os.ModePerm); err != nil {
|
||||
env.t.Fatalf("testutil: could not create directory %q: %v", path, err)
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
func FixtureRelPath(path string) string {
|
||||
normalized := strings.ReplaceAll(path, `\`, "/")
|
||||
if len(normalized) >= 2 && normalized[1] == ':' {
|
||||
normalized = normalized[2:]
|
||||
}
|
||||
|
||||
cleaned := pathpkg.Clean("/" + normalized)
|
||||
cleaned = strings.TrimPrefix(cleaned, "/")
|
||||
if cleaned == "." {
|
||||
return ""
|
||||
}
|
||||
|
||||
return filepath.FromSlash(cleaned)
|
||||
}
|
||||
|
||||
func NormalizeTestPath(path string) string {
|
||||
if resolved, err := filepath.EvalSymlinks(path); err == nil {
|
||||
return filepath.Clean(resolved)
|
||||
}
|
||||
|
||||
return filepath.Clean(path)
|
||||
}
|
||||
|
||||
func sanitizeTestName(name string) string {
|
||||
if name == "" {
|
||||
return defaultTestDatabaseName
|
||||
}
|
||||
|
||||
var b strings.Builder
|
||||
lastDash := false
|
||||
for _, r := range strings.ToLower(name) {
|
||||
switch {
|
||||
case unicode.IsLetter(r), unicode.IsDigit(r):
|
||||
b.WriteRune(r)
|
||||
lastDash = false
|
||||
case !lastDash:
|
||||
b.WriteByte('-')
|
||||
lastDash = true
|
||||
}
|
||||
}
|
||||
|
||||
sanitized := strings.Trim(b.String(), "-")
|
||||
if sanitized == "" {
|
||||
return defaultTestDatabaseName
|
||||
}
|
||||
|
||||
return defaultTestDatabaseName + "-" + sanitized
|
||||
}
|
||||
112
internal/testutil/env_test.go
Normal file
112
internal/testutil/env_test.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNewTestEnv_CreatesIsolatedPaths(t *testing.T) {
|
||||
first := NewTestEnv(t)
|
||||
second := NewTestEnv(t)
|
||||
|
||||
assert.NotEqual(t, first.RootDir, second.RootDir)
|
||||
assert.DirExists(t, first.RootDir)
|
||||
assert.DirExists(t, first.DataDir)
|
||||
assert.DirExists(t, first.CacheDir)
|
||||
assert.Equal(t, filepath.Join(first.RootDir, "data"), first.DataDir)
|
||||
assert.Equal(t, filepath.Join(first.RootDir, "data", "cache"), first.CacheDir)
|
||||
|
||||
offlineDir := first.EnsureDataDir("offline", "assets")
|
||||
assert.Equal(t, filepath.Join(first.DataDir, "offline", "assets"), offlineDir)
|
||||
assert.DirExists(t, offlineDir)
|
||||
|
||||
cacheDir := first.EnsureCacheDir("metadata-provider")
|
||||
assert.Equal(t, filepath.Join(first.CacheDir, "metadata-provider"), cacheDir)
|
||||
assert.DirExists(t, cacheDir)
|
||||
assert.NotNil(t, first.Logger())
|
||||
assert.NotNil(t, first.Config())
|
||||
assert.Contains(t, first.Config().Database.Name, "seanime-test-")
|
||||
}
|
||||
|
||||
func TestNewTestEnv_CreatesDatabaseAndCache(t *testing.T) {
|
||||
env := NewTestEnv(t)
|
||||
|
||||
database := env.NewDatabase("")
|
||||
require.NotNil(t, database)
|
||||
require.NotNil(t, database.Gorm())
|
||||
|
||||
cacher := env.NewCacher("continuity")
|
||||
require.NotNil(t, cacher)
|
||||
assert.DirExists(t, env.CachePath("continuity"))
|
||||
}
|
||||
|
||||
func TestNewTestEnv_UsesDefaultsWithoutConfig(t *testing.T) {
|
||||
t.Setenv("TEST_CONFIG_PATH", t.TempDir())
|
||||
|
||||
env := NewTestEnv(t)
|
||||
cfg := env.Config()
|
||||
|
||||
assert.Equal(t, env.DataDir, cfg.Path.DataDir)
|
||||
assert.Contains(t, cfg.Database.Name, defaultTestDatabaseName)
|
||||
assert.DirExists(t, env.DataDir)
|
||||
}
|
||||
|
||||
func TestFixtureRelPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "unix absolute path",
|
||||
input: "/Users/rahim/Downloads/file.mkv",
|
||||
expected: filepath.Join("Users", "rahim", "Downloads", "file.mkv"),
|
||||
},
|
||||
{
|
||||
name: "windows drive path",
|
||||
input: `E:\Anime\Series\Ep1.mkv`,
|
||||
expected: filepath.Join("Anime", "Series", "Ep1.mkv"),
|
||||
},
|
||||
{
|
||||
name: "relative path",
|
||||
input: "fixture/file.txt",
|
||||
expected: filepath.Join("fixture", "file.txt"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.expected, FixtureRelPath(tt.input))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvMustWriteFixtureFile_RootsUnderTempDir(t *testing.T) {
|
||||
env := NewTestEnv(t)
|
||||
target := env.MustWriteFixtureFile("/Users/rahim/Downloads/media.mkv", []byte("fixture"))
|
||||
|
||||
require.FileExists(t, target)
|
||||
assert.Equal(t, env.FixturePath("/Users/rahim/Downloads/media.mkv"), target)
|
||||
assert.True(t, strings.HasPrefix(target, env.RootDir))
|
||||
}
|
||||
|
||||
func TestRequireSampleVideoPath_UsesEnvOverride(t *testing.T) {
|
||||
t.Setenv(SampleVideoPathEnv, "/tmp/sample.mkv")
|
||||
|
||||
assert.Equal(t, "/tmp/sample.mkv", RequireSampleVideoPath(t))
|
||||
}
|
||||
|
||||
func TestShouldRecordAnilistFixtures(t *testing.T) {
|
||||
t.Setenv(RecordAnilistFixturesEnvName, "true")
|
||||
assert.True(t, ShouldRecordAnilistFixtures())
|
||||
|
||||
t.Setenv(RecordAnilistFixturesEnvName, "false")
|
||||
assert.False(t, ShouldRecordAnilistFixtures())
|
||||
|
||||
t.Setenv(RecordAnilistFixturesEnvName, "not-a-bool")
|
||||
assert.False(t, ShouldRecordAnilistFixtures())
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"seanime/internal/extension"
|
||||
hibiketorrent "seanime/internal/extension/hibike/torrent"
|
||||
"seanime/internal/library/anime"
|
||||
"seanime/internal/testutil"
|
||||
itorrent "seanime/internal/torrents/torrent"
|
||||
"seanime/internal/util"
|
||||
"seanime/internal/util/filecache"
|
||||
@@ -19,8 +18,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// FakeSearchProvider is a fake torrent provider for testing search functionality
|
||||
type FakeSearchProvider struct {
|
||||
// TestSearchProvider is a programmable torrent provider for search tests.
|
||||
type TestSearchProvider struct {
|
||||
SearchResults map[string][]*hibiketorrent.AnimeTorrent // keyed by resolution
|
||||
CanSmartSearch bool
|
||||
SearchCallCount int
|
||||
@@ -29,7 +28,7 @@ type FakeSearchProvider struct {
|
||||
LastBatchSetting bool
|
||||
}
|
||||
|
||||
func (f *FakeSearchProvider) Search(opts hibiketorrent.AnimeSearchOptions) ([]*hibiketorrent.AnimeTorrent, error) {
|
||||
func (f *TestSearchProvider) Search(opts hibiketorrent.AnimeSearchOptions) ([]*hibiketorrent.AnimeTorrent, error) {
|
||||
f.SearchCallCount++
|
||||
f.LastSearchQuery = opts.Query
|
||||
f.LastResolution = ""
|
||||
@@ -42,7 +41,7 @@ func (f *FakeSearchProvider) Search(opts hibiketorrent.AnimeSearchOptions) ([]*h
|
||||
return []*hibiketorrent.AnimeTorrent{}, nil
|
||||
}
|
||||
|
||||
func (f *FakeSearchProvider) SmartSearch(opts hibiketorrent.AnimeSmartSearchOptions) ([]*hibiketorrent.AnimeTorrent, error) {
|
||||
func (f *TestSearchProvider) SmartSearch(opts hibiketorrent.AnimeSmartSearchOptions) ([]*hibiketorrent.AnimeTorrent, error) {
|
||||
f.SearchCallCount++
|
||||
f.LastResolution = opts.Resolution
|
||||
f.LastBatchSetting = opts.Batch
|
||||
@@ -54,19 +53,19 @@ func (f *FakeSearchProvider) SmartSearch(opts hibiketorrent.AnimeSmartSearchOpti
|
||||
return []*hibiketorrent.AnimeTorrent{}, nil
|
||||
}
|
||||
|
||||
func (f *FakeSearchProvider) GetTorrentInfoHash(torrent *hibiketorrent.AnimeTorrent) (string, error) {
|
||||
func (f *TestSearchProvider) GetTorrentInfoHash(torrent *hibiketorrent.AnimeTorrent) (string, error) {
|
||||
return torrent.InfoHash, nil
|
||||
}
|
||||
|
||||
func (f *FakeSearchProvider) GetTorrentMagnetLink(torrent *hibiketorrent.AnimeTorrent) (string, error) {
|
||||
func (f *TestSearchProvider) GetTorrentMagnetLink(torrent *hibiketorrent.AnimeTorrent) (string, error) {
|
||||
return torrent.MagnetLink, nil
|
||||
}
|
||||
|
||||
func (f *FakeSearchProvider) GetLatest() ([]*hibiketorrent.AnimeTorrent, error) {
|
||||
func (f *TestSearchProvider) GetLatest() ([]*hibiketorrent.AnimeTorrent, error) {
|
||||
return []*hibiketorrent.AnimeTorrent{}, nil
|
||||
}
|
||||
|
||||
func (f *FakeSearchProvider) GetSettings() hibiketorrent.AnimeProviderSettings {
|
||||
func (f *TestSearchProvider) GetSettings() hibiketorrent.AnimeProviderSettings {
|
||||
return hibiketorrent.AnimeProviderSettings{
|
||||
CanSmartSearch: f.CanSmartSearch,
|
||||
SmartSearchFilters: nil,
|
||||
@@ -75,10 +74,10 @@ func (f *FakeSearchProvider) GetSettings() hibiketorrent.AnimeProviderSettings {
|
||||
}
|
||||
}
|
||||
|
||||
var _ hibiketorrent.AnimeProvider = (*FakeSearchProvider)(nil)
|
||||
var _ hibiketorrent.AnimeProvider = (*TestSearchProvider)(nil)
|
||||
|
||||
// setupTestAutoSelect creates an AutoSelect instance with a fake provider
|
||||
func setupTestAutoSelect(t *testing.T, provider *FakeSearchProvider) *AutoSelect {
|
||||
// setupTestAutoSelect creates an AutoSelect instance with a test provider.
|
||||
func setupTestAutoSelect(t *testing.T, provider *TestSearchProvider) *AutoSelect {
|
||||
logger := util.NewLogger()
|
||||
|
||||
tempDir := t.TempDir()
|
||||
@@ -87,11 +86,11 @@ func setupTestAutoSelect(t *testing.T, provider *FakeSearchProvider) *AutoSelect
|
||||
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
|
||||
// Create fake extension
|
||||
// Create test extension
|
||||
ext := extension.NewAnimeTorrentProviderExtension(&extension.Extension{
|
||||
ID: "fake-provider",
|
||||
Type: extension.TypeAnimeTorrentProvider,
|
||||
Name: "Fake Provider",
|
||||
Name: "Test Provider",
|
||||
}, provider)
|
||||
|
||||
extensionBankRef.Get().Set("fake-provider", ext)
|
||||
@@ -136,8 +135,6 @@ func createTestMedia(t *testing.T) *anilist.CompleteAnime {
|
||||
}
|
||||
|
||||
func TestSearchFromProvider_SingleResolution(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
media := createTestMedia(t)
|
||||
episodeNumber := 1000
|
||||
|
||||
@@ -146,7 +143,7 @@ func TestSearchFromProvider_SingleResolution(t *testing.T) {
|
||||
{Name: "[Erai-raws] One Piece - 1000 [1080p].mkv", InfoHash: "hash2", Seeders: 150},
|
||||
}
|
||||
|
||||
provider := &FakeSearchProvider{
|
||||
provider := &TestSearchProvider{
|
||||
SearchResults: map[string][]*hibiketorrent.AnimeTorrent{
|
||||
"1080p": t1080p,
|
||||
},
|
||||
@@ -170,8 +167,6 @@ func TestSearchFromProvider_SingleResolution(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSearchFromProvider_MultipleResolutions_FirstSucceeds(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
media := createTestMedia(t)
|
||||
episodeNumber := 1000
|
||||
|
||||
@@ -179,7 +174,7 @@ func TestSearchFromProvider_MultipleResolutions_FirstSucceeds(t *testing.T) {
|
||||
{Name: "[SubsPlease] One Piece - 1000 (1080p).mkv", InfoHash: "hash1", Seeders: 100},
|
||||
}
|
||||
|
||||
provider := &FakeSearchProvider{
|
||||
provider := &TestSearchProvider{
|
||||
SearchResults: map[string][]*hibiketorrent.AnimeTorrent{
|
||||
"1080p": t1080p,
|
||||
"720p": {}, // Empty
|
||||
@@ -204,8 +199,6 @@ func TestSearchFromProvider_MultipleResolutions_FirstSucceeds(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSearchFromProvider_MultipleResolutions_Fallback(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
media := createTestMedia(t)
|
||||
episodeNumber := 1000
|
||||
|
||||
@@ -213,7 +206,7 @@ func TestSearchFromProvider_MultipleResolutions_Fallback(t *testing.T) {
|
||||
{Name: "[SubsPlease] One Piece - 1000 (720p).mkv", InfoHash: "hash1", Seeders: 80},
|
||||
}
|
||||
|
||||
provider := &FakeSearchProvider{
|
||||
provider := &TestSearchProvider{
|
||||
SearchResults: map[string][]*hibiketorrent.AnimeTorrent{
|
||||
"1080p": {}, // Empty, should fallback
|
||||
"720p": t720p,
|
||||
@@ -238,12 +231,10 @@ func TestSearchFromProvider_MultipleResolutions_Fallback(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSearchFromProvider_AllResolutionsFail(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
media := createTestMedia(t)
|
||||
episodeNumber := 1000
|
||||
|
||||
provider := &FakeSearchProvider{
|
||||
provider := &TestSearchProvider{
|
||||
SearchResults: map[string][]*hibiketorrent.AnimeTorrent{
|
||||
"1080p": {},
|
||||
"720p": {},
|
||||
@@ -269,8 +260,6 @@ func TestSearchFromProvider_AllResolutionsFail(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSearchFromProvider_NoResolutionsInProfile(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
media := createTestMedia(t)
|
||||
episodeNumber := 1000
|
||||
|
||||
@@ -278,7 +267,7 @@ func TestSearchFromProvider_NoResolutionsInProfile(t *testing.T) {
|
||||
{Name: "[SubsPlease] One Piece - 1000.mkv", InfoHash: "hash1", Seeders: 100},
|
||||
}
|
||||
|
||||
provider := &FakeSearchProvider{
|
||||
provider := &TestSearchProvider{
|
||||
SearchResults: map[string][]*hibiketorrent.AnimeTorrent{
|
||||
"": tAny, // Empty resolution key for "any"
|
||||
},
|
||||
@@ -302,8 +291,6 @@ func TestSearchFromProvider_NoResolutionsInProfile(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSearchFromProvider_BatchFallback(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
media := createTestMedia(t)
|
||||
episodeNumber := 1
|
||||
|
||||
@@ -311,7 +298,7 @@ func TestSearchFromProvider_BatchFallback(t *testing.T) {
|
||||
{Name: "[SubsPlease] One Piece - 01 (1080p).mkv", InfoHash: "hash1", Seeders: 100},
|
||||
}
|
||||
|
||||
provider := &FakeSearchProvider{
|
||||
provider := &TestSearchProvider{
|
||||
SearchResults: map[string][]*hibiketorrent.AnimeTorrent{
|
||||
"1080p": tSingle,
|
||||
},
|
||||
@@ -335,8 +322,6 @@ func TestSearchFromProvider_BatchFallback(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSearchFromProviders_MultipleProviders(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
media := createTestMedia(t)
|
||||
episodeNumber := 1000
|
||||
|
||||
@@ -345,7 +330,7 @@ func TestSearchFromProviders_MultipleProviders(t *testing.T) {
|
||||
{Name: "[Erai-raws] One Piece - 1000 [1080p].mkv", InfoHash: "hash2", Seeders: 150},
|
||||
}
|
||||
|
||||
provider := &FakeSearchProvider{
|
||||
provider := &TestSearchProvider{
|
||||
SearchResults: map[string][]*hibiketorrent.AnimeTorrent{
|
||||
"1080p": t1080p,
|
||||
},
|
||||
@@ -367,8 +352,6 @@ func TestSearchFromProviders_MultipleProviders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSearchFromProviders_Deduplication(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
media := createTestMedia(t)
|
||||
episodeNumber := 1000
|
||||
|
||||
@@ -378,7 +361,7 @@ func TestSearchFromProviders_Deduplication(t *testing.T) {
|
||||
{Name: "[Erai-raws] One Piece - 1000 [1080p].mkv", InfoHash: "hash2", Seeders: 150},
|
||||
}
|
||||
|
||||
provider := &FakeSearchProvider{
|
||||
provider := &TestSearchProvider{
|
||||
SearchResults: map[string][]*hibiketorrent.AnimeTorrent{
|
||||
"1080p": t1080p,
|
||||
},
|
||||
@@ -400,8 +383,6 @@ func TestSearchFromProviders_Deduplication(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSearch_Integration(t *testing.T) {
|
||||
testutil.InitTestProvider(t, testutil.Anilist())
|
||||
|
||||
media := createTestMedia(t)
|
||||
episodeNumber := 1000
|
||||
|
||||
@@ -409,7 +390,7 @@ func TestSearch_Integration(t *testing.T) {
|
||||
{Name: "[SubsPlease] One Piece - 1000 (720p).mkv", InfoHash: "hash1", Seeders: 100},
|
||||
}
|
||||
|
||||
provider := &FakeSearchProvider{
|
||||
provider := &TestSearchProvider{
|
||||
SearchResults: map[string][]*hibiketorrent.AnimeTorrent{
|
||||
"1080p": {}, // Empty, should fallback to 720p
|
||||
"720p": t720p,
|
||||
@@ -581,14 +562,14 @@ func TestGetProvidersToSearch(t *testing.T) {
|
||||
extensionBankRef := util.NewRef(extension.NewUnifiedBank())
|
||||
|
||||
// Create fake extensions
|
||||
provider1 := &FakeSearchProvider{CanSmartSearch: false}
|
||||
provider1 := &TestSearchProvider{CanSmartSearch: false}
|
||||
ext1 := extension.NewAnimeTorrentProviderExtension(&extension.Extension{
|
||||
ID: "provider1",
|
||||
Type: extension.TypeAnimeTorrentProvider,
|
||||
Name: "Provider 1",
|
||||
}, provider1)
|
||||
|
||||
provider2 := &FakeSearchProvider{CanSmartSearch: false}
|
||||
provider2 := &TestSearchProvider{CanSmartSearch: false}
|
||||
ext2 := extension.NewAnimeTorrentProviderExtension(&extension.Extension{
|
||||
ID: "provider2",
|
||||
Type: extension.TypeAnimeTorrentProvider,
|
||||
|
||||
@@ -2,24 +2,19 @@ package filecache
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"seanime/internal/testutil"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCacherFunctions(t *testing.T) {
|
||||
testutil.InitTestProvider(t)
|
||||
|
||||
tempDir := t.TempDir()
|
||||
t.Log(tempDir)
|
||||
|
||||
cacher, err := NewCacher(filepath.Join(tempDir, "cache"))
|
||||
require.NoError(t, err)
|
||||
cacher, err := NewCacher(filepath.Join(t.TempDir(), "cache"))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create cacher: %v", err)
|
||||
}
|
||||
|
||||
bucket := Bucket{
|
||||
name: "test",
|
||||
@@ -64,12 +59,7 @@ func TestCacherFunctions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCacherSetAndGet(t *testing.T) {
|
||||
cfg := testutil.InitTestProvider(t)
|
||||
|
||||
tempDir := t.TempDir()
|
||||
t.Log(tempDir)
|
||||
|
||||
cacher, err := NewCacher(filepath.Join(cfg.Path.DataDir, "cache"))
|
||||
cacher, err := NewCacher(filepath.Join(t.TempDir(), "cache"))
|
||||
|
||||
bucket := Bucket{
|
||||
name: "test",
|
||||
|
||||
96
scripts/record_anilist_fixtures/main.go
Normal file
96
scripts/record_anilist_fixtures/main.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"seanime/internal/testutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
runPattern string
|
||||
count int
|
||||
verbose bool
|
||||
dryRun bool
|
||||
)
|
||||
|
||||
flag.StringVar(&runPattern, "run", "", "Optional go test -run pattern for limiting fixture refresh")
|
||||
flag.IntVar(&count, "count", 1, "go test count value")
|
||||
flag.BoolVar(&verbose, "v", true, "Run go test with -v")
|
||||
flag.BoolVar(&dryRun, "dry-run", false, "Print the go test command without executing it")
|
||||
flag.Parse()
|
||||
|
||||
configPath := resolveConfigPath()
|
||||
if _, err := os.Stat(configPath); err != nil {
|
||||
fatalf("test config not found at %s; create it from test/config.example.toml first", configPath)
|
||||
}
|
||||
|
||||
cfg := testutil.MustLoadConfig()
|
||||
if !cfg.Flags.EnableAnilistTests {
|
||||
fatalf("AniList tests are disabled in %s; set flags.enable_anilist_tests=true", configPath)
|
||||
}
|
||||
if strings.TrimSpace(cfg.Provider.AnilistJwt) == "" {
|
||||
fatalf("provider.anilist_jwt is empty in %s; fixture recording requires an authenticated AniList token", configPath)
|
||||
}
|
||||
if strings.TrimSpace(cfg.Provider.AnilistUsername) == "" {
|
||||
fmt.Fprintf(os.Stderr, "warning: provider.anilist_username is empty in %s; collection-based refresh flows may not cover user-scoped fixtures\n", configPath)
|
||||
}
|
||||
|
||||
packages := flag.Args()
|
||||
if len(packages) == 0 {
|
||||
packages = []string{"./internal/api/anilist"}
|
||||
}
|
||||
|
||||
args := []string{"test"}
|
||||
if verbose {
|
||||
args = append(args, "-v")
|
||||
}
|
||||
if count > 0 {
|
||||
args = append(args, fmt.Sprintf("-count=%d", count))
|
||||
}
|
||||
if runPattern != "" {
|
||||
args = append(args, "-run", runPattern)
|
||||
}
|
||||
args = append(args, packages...)
|
||||
|
||||
cmd := exec.Command("go", args...)
|
||||
cmd.Dir = testutil.ProjectRoot()
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Env = append(os.Environ(), testutil.RecordAnilistFixturesEnvName+"=true")
|
||||
|
||||
fmt.Fprintf(os.Stderr, "Using test config: %s\n", configPath)
|
||||
fmt.Fprintf(os.Stderr, "Recording AniList fixtures with %s=true\n", testutil.RecordAnilistFixturesEnvName)
|
||||
fmt.Fprintf(os.Stderr, "Running: go %s\n", strings.Join(args, " "))
|
||||
|
||||
if dryRun {
|
||||
return
|
||||
}
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
os.Exit(exitErr.ExitCode())
|
||||
}
|
||||
fatalf("failed to run go test: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func resolveConfigPath() string {
|
||||
configDir := os.Getenv("TEST_CONFIG_PATH")
|
||||
if configDir == "" {
|
||||
configDir = filepath.Join(testutil.ProjectRoot(), "test")
|
||||
}
|
||||
|
||||
return filepath.Join(configDir, "config.toml")
|
||||
}
|
||||
|
||||
func fatalf(format string, args ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, format+"\n", args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -29,6 +29,7 @@ torbox_api_key = ""
|
||||
|
||||
[path]
|
||||
dataDir = ''
|
||||
sampleVideoPath = ''
|
||||
|
||||
[database]
|
||||
name = 'seanime-test'
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user