using Harmonia.Core.Engine; using Harmonia.Core.Models; using Harmonia.Core.Player; using Harmonia.Core.Playlists; using NSubstitute; using NSubstitute.ExceptionExtensions; using Shouldly; namespace Harmonia.Tests; public class TestAudioPlayer(IAudioEngine audioEngine, IPlaylistRepository playlistRepository) : AudioPlayer(audioEngine, playlistRepository) { internal void SetPlaylist(Playlist playlist) { Playlist = playlist; } internal int GetPlayingSongIndex() { if (Playlist == null) return -1; if (PlayingSong == null) return -1; return Playlist.Songs.IndexOf(PlayingSong); } } public class AudioPlayerTests { private readonly IAudioEngine _audioEngine; private readonly IPlaylistRepository _playlistRepository; private readonly PlaylistSong[] _playlistSongs; private readonly TestAudioPlayer _audioPlayer; public AudioPlayerTests() { _audioEngine = Substitute.For(); _audioEngine.LoadAsync("Song1.mp3").Returns(true); _audioEngine.LoadAsync("Song2.mp3").Returns(false); _audioEngine.LoadAsync("Song3.mp3").Returns(true); _audioEngine.LoadAsync("Song4.mp3").Throws(new FileNotFoundException()); _audioEngine.LoadAsync("Song5.mp3").Returns(false); _audioEngine.LoadAsync("Song6.mp3").Returns(true); _audioEngine.LoadAsync("Song7.mp3").Returns(true); Song[] songs = [ new Song() { FileName = "Song1.mp3" }, new Song() { FileName = "Song2.mp3" }, new Song() { FileName = "Song3.mp3" }, new Song() { FileName = "Song4.mp3" }, new Song() { FileName = "Song5.mp3" }, new Song() { FileName = "Song6.mp3" }, new Song() { FileName = "Song7.mp3" } ]; Playlist playlist = new() { Name = "Playlist1" }; playlist.AddSongs(songs); _playlistSongs = [.. playlist.Songs]; _playlistRepository = Substitute.For(); _playlistRepository.Get().Returns([playlist]); //_playlistRepository.GetPlaylist(_playlistSongs[0]).Returns(playlist); _audioPlayer = new TestAudioPlayer(_audioEngine, _playlistRepository); _audioPlayer.SetPlaylist(playlist); //await _audioPlayer.LoadAsync(_playlistSongs[0], PlaybackMode.LoadOnly); } [Theory] [InlineData(0, true)] [InlineData(1, false)] [InlineData(2, true)] [InlineData(3, false)] [InlineData(4, false)] [InlineData(5, true)] [InlineData(6, true)] [InlineData(7, false)] public async Task Load_Song(int index, bool expectedResult) { bool result = await _audioPlayer.LoadAsync(index); result.ShouldBe(expectedResult); } [Theory] [InlineData(0, 2)] [InlineData(2, 5)] [InlineData(5, 6)] [InlineData(6, 0)] public async Task Load_Next_Song(int index, int expectedResult) { await _audioPlayer.LoadAsync(index); await _audioPlayer.NextAsync(); int currentIndex = _audioPlayer.GetPlayingSongIndex(); currentIndex.ShouldBe(expectedResult); } [Theory] [InlineData(0, 0, RepeatState.Off, 0)] [InlineData(0, 6, RepeatState.RepeatAll, 0)] [InlineData(6, 5, RepeatState.Off, 0)] [InlineData(6, 6, RepeatState.Off, 6)] public async Task Load_Previous_Song(int index, int expectedResult, RepeatState repeatState = RepeatState.Off, double position = 0) { await _audioPlayer.LoadAsync(index, PlaybackMode.LoadAndPlay); _audioPlayer.RepeatState = repeatState; _audioPlayer.Position = position; await _audioPlayer.PreviousAsync(); int currentIndex = _audioPlayer.GetPlayingSongIndex(); currentIndex.ShouldBe(expectedResult); } [Theory] [InlineData(0, 2, RepeatState.Off)] [InlineData(0, 0, RepeatState.RepeatOne)] public async Task Song_Finshed(int index, int expectedResult, RepeatState repeatState = RepeatState.Off) { await _audioPlayer.LoadAsync(index, PlaybackMode.LoadAndPlay); _audioPlayer.RepeatState = repeatState; TaskCompletionSource taskCompletionSource = new(); _audioEngine.StreamFinished += (sender, eventArgs) => { taskCompletionSource.SetResult(true); }; _audioEngine.StreamFinished += Raise.EventWith(_audioEngine, new()); await taskCompletionSource.Task; int currentIndex = _audioPlayer.GetPlayingSongIndex(); currentIndex.ShouldBe(expectedResult); } }