From 73a2fe3da27739407d23bb1326e21509e806bc06 Mon Sep 17 00:00:00 2001 From: lieght <49651652+BAFGdeJong@users.noreply.github.com> Date: Sat, 11 Oct 2025 23:08:28 +0200 Subject: [PATCH] Unit tests for MusicManager.java --- .../toop/framework/audio/MusicManager.java | 57 ++++-- .../framework/audio/MusicManagerTest.java | 185 ++++++++++++++++++ 2 files changed, 222 insertions(+), 20 deletions(-) create mode 100644 framework/src/test/java/org/toop/framework/audio/MusicManagerTest.java diff --git a/framework/src/main/java/org/toop/framework/audio/MusicManager.java b/framework/src/main/java/org/toop/framework/audio/MusicManager.java index fa49438..01ad94d 100644 --- a/framework/src/main/java/org/toop/framework/audio/MusicManager.java +++ b/framework/src/main/java/org/toop/framework/audio/MusicManager.java @@ -28,13 +28,10 @@ public class MusicManager implements org.toop.framework } // Used in unit testing - MusicManager(Class type, Dispatcher dispatcher, ResourceManager resourceManager) { + MusicManager(List resources, Dispatcher dispatcher) { this.dispatcher = dispatcher; - this.resources = new ArrayList<>(resourceManager.getAllOfType((Class) type) - .stream() - .map(e -> (T) e.getResource()) - .toList()); - createShuffled(); + this.resources = new ArrayList<>(resources); + backgroundMusic.addAll(resources); } @Override @@ -42,7 +39,7 @@ public class MusicManager implements org.toop.framework return backgroundMusic; } - private void addBackgroundMusic(T musicAsset) { + void addBackgroundMusic(T musicAsset) { backgroundMusic.add(musicAsset); } @@ -65,6 +62,20 @@ public class MusicManager implements org.toop.framework playCurrentTrack(); } + // Used in testing + void play(int index) { + if (playing) { + logger.warn("MusicManager is already playing."); + return; + } + + if (backgroundMusic.isEmpty()) return; + + playingIndex = index; + playing = true; + playCurrentTrack(); + } + private void playCurrentTrack() { if (playingIndex >= backgroundMusic.size()) { playingIndex = 0; @@ -80,20 +91,26 @@ public class MusicManager implements org.toop.framework dispatcher.run(() -> { current.play(); - current.setOnEnd(() -> { - playingIndex++; - playCurrentTrack(); - }); + setTrackRunnable(current); - current.setOnError(() -> { - logger.error("Error playing track: {}", current); - backgroundMusic.remove(current); - if (!backgroundMusic.isEmpty()) { - playCurrentTrack(); - } else { - playing = false; - } - }); + }); + } + + private void setTrackRunnable(T track) { + track.setOnEnd(() -> { + playingIndex++; + playCurrentTrack(); + }); + + track.setOnError(() -> { + logger.error("Error playing track: {}", track); + backgroundMusic.remove(track); + + if (!backgroundMusic.isEmpty()) { + playCurrentTrack(); + } else { + playing = false; + } }); } diff --git a/framework/src/test/java/org/toop/framework/audio/MusicManagerTest.java b/framework/src/test/java/org/toop/framework/audio/MusicManagerTest.java new file mode 100644 index 0000000..1e46274 --- /dev/null +++ b/framework/src/test/java/org/toop/framework/audio/MusicManagerTest.java @@ -0,0 +1,185 @@ +package org.toop.framework.audio; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.toop.framework.audio.interfaces.Dispatcher; +import org.toop.framework.resource.resources.BaseResource; +import org.toop.framework.resource.types.AudioResource; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class MockAudioResource extends BaseResource implements AudioResource { + boolean played = false; + boolean stopped = false; + Runnable onEnd; + Runnable onError; + + public MockAudioResource(String name) { + super(new File(name)); + } + + public void triggerError() { + if (onError != null) { + onError.run(); + } + } + + public void triggerEnd() { + if (onEnd != null) { + onEnd.run(); + } + } + + @Override + public void play() { + played = true; + } + + @Override + public void stop() { + stopped = true; + } + + @Override + public void setOnEnd(Runnable callback) { + onEnd = callback; + } + + @Override + public void setOnError(Runnable callback) { + onError = callback; + } + + @Override + public void updateVolume(double volume) {} +} + +public class MusicManagerTest { + + private Dispatcher dispatcher; + private MockAudioResource track1; + private MockAudioResource track2; + private MockAudioResource track3; + private MusicManager manager; + + @BeforeEach + void setUp() { + dispatcher = Runnable::run; + + track1 = new MockAudioResource("track1"); + track2 = new MockAudioResource("track2"); + track3 = new MockAudioResource("track3"); + + List resources = List.of(track1, track2, track3); + + manager = new MusicManager<>(resources, dispatcher); + } + + @Test + void testPlaySingleTrack() { + manager.play(); + assertTrue(track1.played || track2.played || track3.played, + "At least one track should have played"); + } + + @Test + void testPlayMultipleTimesDoesNotRestart() { + manager.play(); + track1.played = false; + manager.play(); + assertFalse(track1.played, "Second play call should not restart tracks"); + } + + @Test + void testStopStopsAllTracks() { + manager.play(); + manager.stop(); + assertTrue(track1.stopped && track2.stopped && track3.stopped, + "All tracks should be stopped"); + } + + @Test + void testAutoAdvanceTracks() { + track1.played = false; + track2.played = false; + track3.played = false; + + manager.play(); + track1.triggerEnd(); + track2.triggerEnd(); + + assertTrue(track1.played, "Track1 should play, played %s instead"); + assertTrue(track2.played, "Track2 should play after track1 ends"); + assertTrue(track3.played, "Track3 should play after track2 ends"); + } + + @Test + void testTrackErrorRemovesTrackAndPlaysNext() { + manager.play(); + track1.triggerError(); + + assertFalse(manager.getActiveAudio().contains(track1), + "Track1 should be removed after error"); + assertTrue(track2.played, "Track2 should play after track1 error"); + } + + @Test + void testPlayWithEmptyPlaylistDoesNothing() { + manager.getActiveAudio().clear(); + manager.play(); + assertFalse(track1.played || track2.played || track3.played, + "No tracks should play if playlist is empty"); + } + + @Test + void testMultiplePlayStopSequences() { + manager.play(); + manager.stop(); + manager.play(); + assertTrue(track1.played || track2.played || track3.played, + "Tracks should play again after stopping"); + } + + @Test + void testPlayingIndexWrapsAround() { + track1.played = false; + track2.played = false; + track3.played = false; + + manager.play(); + track1.triggerEnd(); + track2.triggerEnd(); + track3.triggerEnd(); + + assertTrue(track1.played, "Track1 should play again after loop"); + assertTrue(track2.played, "Track2 should play"); + assertTrue(track3.played, "Track3 should play"); + } + + /** + * Test for many tracks playing sequentially one after another + */ + @Test + void testSequentialMultipleTracks() { + List manyTracks = new ArrayList<>(); + for (int i = 1; i <= 1_000; i++) { + manyTracks.add(new MockAudioResource("track" + i)); + } + + MusicManager multiManager = new MusicManager<>(manyTracks, dispatcher); + + for (int i = 0; i < manyTracks.size() - 1; i++) { + multiManager.play(); + manyTracks.get(i).triggerEnd(); + } + + for (int i = 0; i < manyTracks.size(); i++) { + assertTrue(manyTracks.get(i).played, "Track " + (i + 1) + " should have played sequentially"); + } + } +} +