Short songs (#30): a quiz settings switch and a Seconds per song row (30 by default, 10-120 in steps of 5), saved with the quiz settings. Only part of each quiz song plays, from a random point 10-60% into it, picked once per song so restart and repeat play the same part. The progress bar, time and seeking stay within the part, a hidden beginning counts inside it, and its end counts as the song ending (repeat, stop or go to the next song as set). Random songs (#51): the low-played switch in Settings is now a Normal / Low played / Classic choice, stored as Settings.random_mode and not saved. fetch_random_song(mode) picks /music/rand, /music/rand/low or /music/rand/classic. Closes #30 Closes #51 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
191 lines
5.6 KiB
GDScript
191 lines
5.6 KiB
GDScript
extends GdUnitTestSuite
|
|
## Short songs: only a part of each quiz song plays, from a random point picked once per
|
|
## song, and the end of the part counts as the song ending.
|
|
|
|
## How long the test song is, in seconds.
|
|
const SONG_SECONDS: float = 60.0
|
|
|
|
var _snapshot: AutoloadSnapshot
|
|
var _runner: GdUnitSceneRunner
|
|
var _player: MusicPlayer
|
|
|
|
|
|
func before_test() -> void:
|
|
_snapshot = AutoloadSnapshot.take([Settings, Playlist])
|
|
Settings.short_songs = true
|
|
Settings.short_song_seconds = 20
|
|
Settings.hide_beginning = false
|
|
Settings.hide_length = false
|
|
Settings.auto_repeat_song = false
|
|
Settings.stop_after_current = true
|
|
Playlist.song_object_array.clear()
|
|
_runner = scene_runner("res://player/MusicPlayer.tscn")
|
|
_player = _runner.scene()
|
|
|
|
|
|
func after_test() -> void:
|
|
_player.audio_player.stop()
|
|
_snapshot.restore()
|
|
|
|
|
|
# A silent song of [param seconds], in the playlist
|
|
func _add_song(seconds: float = SONG_SECONDS) -> SongObject:
|
|
var song: AudioStreamWAV = AudioStreamWAV.new()
|
|
song.format = AudioStreamWAV.FORMAT_8_BITS
|
|
song.mix_rate = 8000
|
|
var silence: PackedByteArray = []
|
|
silence.resize(int(seconds * song.mix_rate))
|
|
song.data = silence
|
|
var song_object: SongObject = SongObject.new()
|
|
song_object.song = song
|
|
song_object.song_number = Playlist.song_object_array.size()
|
|
Playlist.add_to_playlist(song_object)
|
|
return song_object
|
|
|
|
|
|
func _play(song_object: SongObject) -> void:
|
|
await _player.play_song_object(song_object.song_number)
|
|
await _runner.simulate_frames(2)
|
|
|
|
|
|
func test_part_starts_between_ten_and_sixty_percent_in() -> void:
|
|
for i: int in 20:
|
|
var song_object: SongObject = _add_song()
|
|
_player.choose_part(song_object, song_object.song)
|
|
|
|
assert_float(song_object.short_start).is_between(SONG_SECONDS * 0.1, SONG_SECONDS * 0.6)
|
|
assert_float(_player.part_length()).is_equal(20.0)
|
|
|
|
|
|
func test_part_is_picked_once_per_song() -> void:
|
|
var song_object: SongObject = _add_song()
|
|
_player.choose_part(song_object, song_object.song)
|
|
var start: float = song_object.short_start
|
|
|
|
_player.choose_part(song_object, song_object.song)
|
|
|
|
assert_float(song_object.short_start).is_equal(start)
|
|
|
|
|
|
func test_part_always_fits_in_the_song() -> void:
|
|
Settings.short_song_seconds = 50
|
|
for i: int in 20:
|
|
var song_object: SongObject = _add_song()
|
|
_player.choose_part(song_object, song_object.song)
|
|
|
|
assert_float(song_object.short_start + 50).is_less_equal(SONG_SECONDS)
|
|
|
|
|
|
func test_song_shorter_than_the_part_plays_whole() -> void:
|
|
var song_object: SongObject = _add_song(15.0)
|
|
|
|
await _play(song_object)
|
|
|
|
assert_float(_player.part_length()).is_equal_approx(15.0, 0.01)
|
|
assert_float(song_object.short_start).is_equal(-1.0)
|
|
|
|
|
|
func test_whole_song_plays_with_short_songs_off() -> void:
|
|
Settings.short_songs = false
|
|
var song_object: SongObject = _add_song()
|
|
|
|
await _play(song_object)
|
|
|
|
assert_float(_player.part_length()).is_equal_approx(SONG_SECONDS, 0.01)
|
|
assert_float(_player.position_in_part()).is_less(1.0)
|
|
|
|
|
|
func test_song_starts_at_its_part_and_shows_the_part_length() -> void:
|
|
var song_object: SongObject = _add_song()
|
|
|
|
await _play(song_object)
|
|
|
|
assert_float(_player.audio_player.get_playback_position()) \
|
|
.is_greater_equal(song_object.short_start - 0.01)
|
|
assert_float(_player.position_in_part()).is_less(1.0)
|
|
assert_float(_player.progress_slider.max_value).is_equal(20.0)
|
|
assert_str(_player.music_time_label.text).ends_with("/ 00:20")
|
|
|
|
|
|
func test_seeking_stays_inside_the_part() -> void:
|
|
var song_object: SongObject = _add_song()
|
|
await _play(song_object)
|
|
|
|
_player.seek(500)
|
|
|
|
assert_float(_player.progress_slider.value).is_equal(20.0)
|
|
assert_float(_player.playback_position) \
|
|
.is_equal_approx(song_object.short_start + 20.0, 0.01)
|
|
|
|
|
|
func test_end_of_the_part_stops_the_song() -> void:
|
|
var song_object: SongObject = _add_song()
|
|
await _play(song_object)
|
|
|
|
_player.seek(19.9)
|
|
await await_millis(300)
|
|
|
|
assert_bool(_player.song_finished).is_true()
|
|
assert_bool(_player.audio_player.playing).is_false()
|
|
|
|
|
|
func test_end_of_the_part_repeats_it_with_auto_repeat() -> void:
|
|
Settings.auto_repeat_song = true
|
|
var song_object: SongObject = _add_song()
|
|
await _play(song_object)
|
|
|
|
_player.seek(19.9)
|
|
await await_millis(300)
|
|
|
|
assert_bool(_player.audio_player.playing).is_true()
|
|
assert_float(_player.position_in_part()).is_less(1.0)
|
|
assert_float(_player.audio_player.get_playback_position()) \
|
|
.is_greater_equal(song_object.short_start - 0.01)
|
|
|
|
|
|
func test_end_of_the_part_goes_to_the_next_song_without_stop_after_current() -> void:
|
|
Settings.stop_after_current = false
|
|
var song_object: SongObject = _add_song()
|
|
await _play(song_object)
|
|
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_player))
|
|
|
|
_player.seek(19.9)
|
|
|
|
await signals.wait_until(1000).is_emitted("play_next_song")
|
|
|
|
|
|
func test_restart_plays_the_same_part_again() -> void:
|
|
var song_object: SongObject = _add_song()
|
|
await _play(song_object)
|
|
_player.seek(10)
|
|
|
|
_player.restart()
|
|
await _runner.simulate_frames(2)
|
|
|
|
assert_float(_player.position_in_part()).is_less(1.0)
|
|
assert_float(_player.audio_player.get_playback_position()) \
|
|
.is_greater_equal(song_object.short_start - 0.01)
|
|
|
|
|
|
func test_hidden_beginning_counts_inside_the_part() -> void:
|
|
Settings.hide_beginning = true
|
|
Settings.hide_for_seconds = 5.0
|
|
var song_object: SongObject = _add_song()
|
|
|
|
await _play(song_object)
|
|
|
|
assert_str(_player.music_time_label.text).is_equal("??:?? / 00:20")
|
|
_player.seek(6)
|
|
await _runner.simulate_frames(2)
|
|
assert_str(_player.music_time_label.text).starts_with("00:06")
|
|
|
|
|
|
func test_other_sounds_always_play_whole() -> void:
|
|
var song_object: SongObject = _add_song()
|
|
await _play(song_object)
|
|
|
|
_player.play_song(_add_song(30.0).song)
|
|
|
|
assert_float(_player.part_length()).is_equal_approx(30.0, 0.01)
|
|
assert_float(_player.position_in_part()).is_less(1.0)
|