🏡 index : quine-global/quintodrome.git

package tests

import (
	"context"
	"sync"

	"github.com/navidrome/navidrome/model"
)

type MockDataStore struct {
	RealDS               model.DataStore
	MockedLibrary        model.LibraryRepository
	MockedFolder         model.FolderRepository
	MockedGenre          model.GenreRepository
	MockedAlbum          model.AlbumRepository
	MockedArtist         model.ArtistRepository
	MockedMediaFile      model.MediaFileRepository
	MockedTag            model.TagRepository
	MockedUser           model.UserRepository
	MockedProperty       model.PropertyRepository
	MockedPlayer         model.PlayerRepository
	MockedPlaylist       model.PlaylistRepository
	MockedPlayQueue      model.PlayQueueRepository
	MockedShare          model.ShareRepository
	MockedTranscoding    model.TranscodingRepository
	MockedUserProps      model.UserPropsRepository
	MockedScrobbleBuffer model.ScrobbleBufferRepository
	MockedScrobble       model.ScrobbleRepository
	MockedRadio          model.RadioRepository
	MockedPlugin         model.PluginRepository
	MockedArtwork        model.ArtworkRepository
	MockedArtworkQueue   model.ArtworkQueueRepository
	scrobbleBufferMu     sync.Mutex
	repoMu               sync.Mutex

	// GC tracking
	GCCalled bool
	GCError  error
}

func (db *MockDataStore) Library() model.LibraryRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedLibrary != nil {
		return db.MockedLibrary
	}
	if db.RealDS != nil {
		return db.RealDS.Library()
	}
	db.MockedLibrary = &MockLibraryRepo{}
	return db.MockedLibrary
}

func (db *MockDataStore) Folder() model.FolderRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedFolder != nil {
		return db.MockedFolder
	}
	if db.RealDS != nil {
		return db.RealDS.Folder()
	}
	db.MockedFolder = struct{ model.FolderRepository }{}
	return db.MockedFolder
}

func (db *MockDataStore) Tag() model.TagRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedTag != nil {
		return db.MockedTag
	}
	if db.RealDS != nil {
		return db.RealDS.Tag()
	}
	db.MockedTag = &MockTagRepo{}
	return db.MockedTag
}

func (db *MockDataStore) Album() model.AlbumRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedAlbum != nil {
		return db.MockedAlbum
	}
	if db.RealDS != nil {
		return db.RealDS.Album()
	}
	db.MockedAlbum = CreateMockAlbumRepo()
	return db.MockedAlbum
}

func (db *MockDataStore) Artist() model.ArtistRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedArtist != nil {
		return db.MockedArtist
	}
	if db.RealDS != nil {
		return db.RealDS.Artist()
	}
	db.MockedArtist = CreateMockArtistRepo()
	return db.MockedArtist
}

func (db *MockDataStore) MediaFile() model.MediaFileRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.RealDS != nil && db.MockedMediaFile == nil {
		return db.RealDS.MediaFile()
	}
	if db.MockedMediaFile == nil {
		db.MockedMediaFile = CreateMockMediaFileRepo()
	}
	return db.MockedMediaFile
}

func (db *MockDataStore) Genre() model.GenreRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedGenre != nil {
		return db.MockedGenre
	}
	if db.RealDS != nil {
		return db.RealDS.Genre()
	}
	db.MockedGenre = &MockedGenreRepo{}
	return db.MockedGenre
}

func (db *MockDataStore) Playlist() model.PlaylistRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedPlaylist != nil {
		return db.MockedPlaylist
	}
	if db.RealDS != nil {
		return db.RealDS.Playlist()
	}
	db.MockedPlaylist = CreateMockPlaylistRepo()
	return db.MockedPlaylist
}

func (db *MockDataStore) PlayQueue() model.PlayQueueRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedPlayQueue != nil {
		return db.MockedPlayQueue
	}
	if db.RealDS != nil {
		return db.RealDS.PlayQueue()
	}
	db.MockedPlayQueue = &MockPlayQueueRepo{}
	return db.MockedPlayQueue
}

func (db *MockDataStore) UserProps() model.UserPropsRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedUserProps != nil {
		return db.MockedUserProps
	}
	if db.RealDS != nil {
		return db.RealDS.UserProps()
	}
	db.MockedUserProps = &MockedUserPropsRepo{}
	return db.MockedUserProps
}

func (db *MockDataStore) Property() model.PropertyRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedProperty != nil {
		return db.MockedProperty
	}
	if db.RealDS != nil {
		return db.RealDS.Property()
	}
	db.MockedProperty = &MockedPropertyRepo{}
	return db.MockedProperty
}

func (db *MockDataStore) Share() model.ShareRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedShare != nil {
		return db.MockedShare
	}
	if db.RealDS != nil {
		return db.RealDS.Share()
	}
	db.MockedShare = &MockShareRepo{}
	return db.MockedShare
}

func (db *MockDataStore) User() model.UserRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedUser != nil {
		return db.MockedUser
	}
	if db.RealDS != nil {
		return db.RealDS.User()
	}
	db.MockedUser = CreateMockUserRepo()
	return db.MockedUser
}

func (db *MockDataStore) Transcoding() model.TranscodingRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedTranscoding != nil {
		return db.MockedTranscoding
	}
	if db.RealDS != nil {
		return db.RealDS.Transcoding()
	}
	db.MockedTranscoding = struct{ model.TranscodingRepository }{}
	return db.MockedTranscoding
}

func (db *MockDataStore) Player() model.PlayerRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedPlayer != nil {
		return db.MockedPlayer
	}
	if db.RealDS != nil {
		return db.RealDS.Player()
	}
	db.MockedPlayer = CreateMockPlayerRepo()
	return db.MockedPlayer
}

func (db *MockDataStore) ScrobbleBuffer() model.ScrobbleBufferRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.RealDS != nil && db.MockedScrobbleBuffer == nil {
		return db.RealDS.ScrobbleBuffer()
	}
	db.scrobbleBufferMu.Lock()
	defer db.scrobbleBufferMu.Unlock()
	if db.MockedScrobbleBuffer == nil {
		db.MockedScrobbleBuffer = &MockedScrobbleBufferRepo{}
	}
	return db.MockedScrobbleBuffer
}

func (db *MockDataStore) Scrobble() model.ScrobbleRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedScrobble != nil {
		return db.MockedScrobble
	}
	if db.RealDS != nil {
		return db.RealDS.Scrobble()
	}
	db.MockedScrobble = &MockScrobbleRepo{}
	return db.MockedScrobble
}

func (db *MockDataStore) Radio() model.RadioRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedRadio != nil {
		return db.MockedRadio
	}
	if db.RealDS != nil {
		return db.RealDS.Radio()
	}
	db.MockedRadio = CreateMockedRadioRepo()
	return db.MockedRadio
}

func (db *MockDataStore) Plugin() model.PluginRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedPlugin != nil {
		return db.MockedPlugin
	}
	if db.RealDS != nil {
		return db.RealDS.Plugin()
	}
	db.MockedPlugin = CreateMockPluginRepo()
	return db.MockedPlugin
}

func (db *MockDataStore) Artwork() model.ArtworkRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	return db.artworkLocked()
}

// artworkLocked is the body of Artwork for callers already holding repoMu; repoMu is a plain
// Mutex, so re-entering through the exported method would deadlock.
func (db *MockDataStore) artworkLocked() model.ArtworkRepository {
	if db.MockedArtwork != nil {
		return db.MockedArtwork
	}
	if db.RealDS != nil {
		return db.RealDS.Artwork()
	}
	db.MockedArtwork = CreateMockArtworkRepo()
	return db.MockedArtwork
}

func (db *MockDataStore) ArtworkQueue() model.ArtworkQueueRepository {
	db.repoMu.Lock()
	defer db.repoMu.Unlock()
	if db.MockedArtworkQueue != nil {
		return db.MockedArtworkQueue
	}
	if db.RealDS != nil {
		return db.RealDS.ArtworkQueue()
	}
	q := CreateMockArtworkQueueRepo()
	if aw, ok := db.artworkLocked().(*MockArtworkRepo); ok {
		q.ItemArtworkSource = aw
	}
	db.MockedArtworkQueue = q
	return db.MockedArtworkQueue
}

func (db *MockDataStore) WithTx(block func(tx model.DataStore) error, label ...string) error {
	return block(db)
}

func (db *MockDataStore) WithTxImmediate(block func(tx model.DataStore) error, label ...string) error {
	return block(db)
}

func (db *MockDataStore) WithTxRetry(ctx context.Context, block func(ctx context.Context, tx model.DataStore) error, label ...string) error {
	return block(ctx, db)
}

func (db *MockDataStore) GC(context.Context, ...int) error {
	db.GCCalled = true
	if db.GCError != nil {
		return db.GCError
	}
	return nil
}