Buttons get 12 px of side padding. The top bar buttons, the quiz toolbar and Show answer/Next are laid out in rows with 12 px gaps and are all 36 px tall, and the ±1 buttons use a compact StepButton style. "Randomize new track" is now "Next song". Player rows show the name and the score apart, alternate like the other lists and highlight the character under the mouse. The name field is a LineEdit with a 10-letter limit; blank and duplicate names are refused, and a full list says "Up to 7 players". Remove buttons update when editing is switched instead of every frame, and the spacer panels are gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
342 lines
11 KiB
GDScript
342 lines
11 KiB
GDScript
extends MainWindowTestSuite
|
|
## Playing from a music folder instead of the server: soundtrack folders and prepared
|
|
## quizzes, with nothing but the characters asked from the server.
|
|
|
|
var _root: String
|
|
var _settings: SettingsPopup
|
|
var _top_bar: TopBar
|
|
|
|
|
|
func before_test() -> void:
|
|
_root = create_temp_dir("offline_%d" % randi())
|
|
await super()
|
|
_settings = _window.get_node("SettingsPopup")
|
|
_top_bar = _window.get_node("TopBar")
|
|
|
|
|
|
func _song(relative_path: String) -> void:
|
|
var path: String = _root.path_join(relative_path)
|
|
DirAccess.make_dir_recursive_absolute(path.get_base_dir())
|
|
FileAccess.open(path, FileAccess.WRITE).store_buffer(
|
|
FileAccess.get_file_as_bytes("res://tests/data/short.mp3"))
|
|
|
|
|
|
func _soundtrack_folder() -> String:
|
|
_song("Music/Chrono Trigger/Corridors of Time.mp3")
|
|
_song("Music/Final Fantasy VI/Dancing Mad.mp3")
|
|
return _root.path_join("Music")
|
|
|
|
|
|
func _prepared_quiz() -> String:
|
|
for file_name: String in ["02. Ace Combat 7 - Daredevil.mp3", "01. Opening.mp3",
|
|
"10. Banjo Tooie - Cloud Race.mp3"]:
|
|
_song("Quiz/" + file_name)
|
|
return _root.path_join("Quiz")
|
|
|
|
|
|
# Requests to the server other than for characters
|
|
func _server_requests() -> Array[String]:
|
|
return _server.requested_paths.filter(
|
|
func(path: String) -> bool: return !path.begins_with("/character"))
|
|
|
|
|
|
func _use_folder(path: String) -> void:
|
|
_settings.use_music_folder(path)
|
|
await _runner.simulate_frames(2)
|
|
|
|
|
|
# Presses Next and waits until the song plays. Another playing song is stopped first,
|
|
# which takes half a second.
|
|
func _next() -> void:
|
|
_press("SongControls/NextButton")
|
|
await await_millis(700)
|
|
|
|
|
|
func _now_playing() -> Array[String]:
|
|
var now_playing: Node = _quiz.get_node("NowPlaying")
|
|
return [(now_playing.get_node("SoundtrackLabel") as Label).text,
|
|
(now_playing.get_node("SongLabel") as Label).text]
|
|
|
|
|
|
func test_picking_a_folder_makes_no_server_requests() -> void:
|
|
var before: int = _server_requests().size()
|
|
|
|
await _use_folder(_soundtrack_folder())
|
|
await _play_first_song()
|
|
_press("SongControls/ShowAnswerButton")
|
|
_press("QuizToolbar/SoundTestButton")
|
|
_press("QuizToolbar/ResetPlaylistButton")
|
|
await _runner.simulate_frames(2)
|
|
(_window.get_node("%AboutPopup") as AboutPopup).open()
|
|
|
|
assert_array(_server_requests().slice(before)).is_empty()
|
|
|
|
|
|
func test_next_plays_a_song_from_the_folder() -> void:
|
|
await _use_folder(_soundtrack_folder())
|
|
|
|
await _play_first_song()
|
|
|
|
var playing: SongObject = Playlist.song_object_array[Playlist.currently_playing_song]
|
|
assert_str(playing.song_path).starts_with(_root)
|
|
assert_bool((_quiz.get_node("MusicPlayer") as MusicPlayer).audio_player.playing).is_true()
|
|
|
|
|
|
func test_show_answer_shows_the_subfolder_and_the_song() -> void:
|
|
await _use_folder(_soundtrack_folder())
|
|
await _play_first_song()
|
|
|
|
_press("SongControls/ShowAnswerButton")
|
|
|
|
var song: SongObject = Playlist.song_object_array[Playlist.currently_playing_song]
|
|
assert_array(_now_playing()).contains_exactly([song.soundtrack_title, song.song_title])
|
|
assert_array(["Chrono Trigger", "Final Fantasy VI"]).contains([song.soundtrack_title])
|
|
assert_bool(song.song_title.ends_with(".mp3")).is_false()
|
|
|
|
|
|
func test_points_are_given_as_usual() -> void:
|
|
await _use_folder(_soundtrack_folder())
|
|
_add_player("Crono")
|
|
await _play_first_song()
|
|
|
|
await _give_point_with_keybind(1)
|
|
|
|
assert_array(_scores()).contains_exactly([1])
|
|
assert_array(Playlist.song_object_array[0].players_given_point).has_size(1)
|
|
|
|
|
|
func test_inspiration_list_and_search_show_the_subfolders() -> void:
|
|
await _use_folder(_soundtrack_folder())
|
|
|
|
assert_array(_quiz.inspiration_list.soundtracks) \
|
|
.contains_exactly(["Chrono Trigger", "Final Fantasy VI"])
|
|
assert_array((_window.get_node("SearchPopup") as SearchPopup).soundtracks) \
|
|
.contains_exactly(["Chrono Trigger", "Final Fantasy VI"])
|
|
|
|
|
|
func test_server_features_are_off_and_the_folder_is_shown() -> void:
|
|
await _use_folder(_soundtrack_folder())
|
|
|
|
assert_bool(_top_bar.sync_button.disabled).is_true()
|
|
assert_bool(_top_bar.qr_button.disabled).is_true()
|
|
assert_bool(_top_bar.statistics_tab.disabled).is_true()
|
|
assert_bool(_top_bar.offline_label.visible).is_true()
|
|
assert_str(_top_bar.offline_label.text).is_equal("Offline: Music")
|
|
assert_bool(_settings.select_server_button.disabled).is_true()
|
|
assert_bool(_settings.add_to_database_button.disabled).is_true()
|
|
# The config folder holds the cached characters, which are still used offline
|
|
assert_bool(_settings.open_config_folder_button.disabled).is_false()
|
|
|
|
|
|
func test_picking_a_folder_on_the_statistics_tab_goes_to_the_quiz() -> void:
|
|
_window.show_tab(&"statistics")
|
|
|
|
await _use_folder(_soundtrack_folder())
|
|
|
|
assert_bool(_quiz.visible).is_true()
|
|
|
|
|
|
func test_reset_playlist_starts_an_empty_playlist() -> void:
|
|
await _use_folder(_soundtrack_folder())
|
|
await _play_first_song()
|
|
await _next()
|
|
|
|
_press("QuizToolbar/ResetPlaylistButton")
|
|
await _runner.simulate_frames(2)
|
|
|
|
assert_int(Playlist.currently_playing_song).is_equal(-1)
|
|
assert_bool(Playlist.song_object_array.all(
|
|
func(song: SongObject) -> bool: return !song.has_played)).is_true()
|
|
|
|
|
|
func test_prepared_quiz_plays_in_order_and_shows_only_the_title() -> void:
|
|
await _use_folder(_prepared_quiz())
|
|
assert_bool(_settings.play_order_row.visible).is_true()
|
|
|
|
await _play_first_song()
|
|
_press("SongControls/ShowAnswerButton")
|
|
|
|
assert_array(_now_playing()).contains_exactly(["", "01. Opening"])
|
|
var row: SongRow = _quiz.music_list_panel.get_node("%MusicList").get_child(0)
|
|
assert_str(row.song_list_label.text).starts_with("1. 01. Opening")
|
|
assert_array(_quiz.inspiration_list.soundtracks).is_empty()
|
|
|
|
|
|
func test_prepared_quiz_stops_after_the_last_song() -> void:
|
|
await _use_folder(_prepared_quiz())
|
|
var titles: Array[String] = []
|
|
|
|
for i: int in 3:
|
|
await _next()
|
|
titles.append(Playlist.song_object_array[Playlist.currently_playing_song].song_title)
|
|
|
|
assert_array(titles).contains_exactly(
|
|
["01. Opening", "02. Ace Combat 7 - Daredevil", "10. Banjo Tooie - Cloud Race"])
|
|
assert_int(Playlist.song_object_array.size()).is_equal(3)
|
|
assert_str((_quiz.get_node("SongControls/NextButton") as Button).text) \
|
|
.is_equal("Show winner")
|
|
|
|
|
|
func test_prepared_quiz_at_random_plays_every_song() -> void:
|
|
await _use_folder(_prepared_quiz())
|
|
|
|
_settings.play_order_button.select(MusicFolder.PlayOrder.RANDOM)
|
|
_settings.play_order_button.item_selected.emit(MusicFolder.PlayOrder.RANDOM)
|
|
await _runner.simulate_frames(2)
|
|
for i: int in 3:
|
|
await _next()
|
|
|
|
assert_int(Settings.music_folder.play_order).is_equal(MusicFolder.PlayOrder.RANDOM)
|
|
var titles: Array = Playlist.song_object_array.map(
|
|
func(song: SongObject) -> String: return song.song_title)
|
|
assert_array(titles).contains_exactly_in_any_order(
|
|
["01. Opening", "02. Ace Combat 7 - Daredevil", "10. Banjo Tooie - Cloud Race"])
|
|
|
|
|
|
func test_play_order_is_only_shown_for_a_prepared_quiz() -> void:
|
|
await _use_folder(_soundtrack_folder())
|
|
|
|
assert_bool(_settings.play_order_row.visible).is_false()
|
|
|
|
|
|
func test_use_server_goes_back_to_the_server() -> void:
|
|
await _use_folder(_soundtrack_folder())
|
|
var before: int = _server_requests().size()
|
|
|
|
_settings.use_server()
|
|
await _runner.simulate_frames(2)
|
|
|
|
assert_bool(Settings.is_offline()).is_false()
|
|
assert_int(_server_requests().size()).is_greater(before)
|
|
assert_bool(_top_bar.sync_button.disabled).is_false()
|
|
assert_bool(_top_bar.offline_label.visible).is_false()
|
|
assert_bool(_settings.use_server_button.visible).is_false()
|
|
|
|
|
|
func test_folder_without_songs_is_not_used() -> void:
|
|
DirAccess.make_dir_recursive_absolute(_root.path_join("Empty"))
|
|
|
|
await _use_folder(_root.path_join("Empty"))
|
|
|
|
assert_bool(Settings.is_offline()).is_false()
|
|
assert_bool(_settings.folder_error_label.visible).is_true()
|
|
assert_str(_settings.folder_error_label.text).is_equal("No songs found in Empty")
|
|
|
|
|
|
func test_settings_panel_fits_its_rows_and_stays_centred() -> void:
|
|
_settings.open()
|
|
await _use_folder(_prepared_quiz())
|
|
await _runner.simulate_frames(1)
|
|
|
|
var panel: Rect2 = _settings.settings_panel.get_global_rect()
|
|
assert_bool(panel.encloses(_settings.rows.get_global_rect())).is_true()
|
|
assert_float(_settings.rows.get_combined_minimum_size().y) \
|
|
.is_less_equal(_settings.rows.size.y)
|
|
assert_float(panel.get_center().y).is_equal_approx(540.0, 1.0)
|
|
|
|
|
|
func test_characters_still_come_from_the_server() -> void:
|
|
var before: int = _server.count("/character/details")
|
|
|
|
await _use_folder(_soundtrack_folder())
|
|
|
|
assert_int(_server.count("/character/details")).is_greater(before)
|
|
|
|
|
|
func _play_whole_quiz() -> void:
|
|
await _play_first_song()
|
|
for i: int in 2:
|
|
await _next()
|
|
|
|
|
|
func test_prepared_quiz_has_no_winning_score() -> void:
|
|
Settings.winning_score = 1
|
|
var crono: PlayerObject = _add_player("Crono")
|
|
await _use_folder(_prepared_quiz())
|
|
await _play_first_song()
|
|
|
|
await _give_point_with_keybind(1)
|
|
await _give_point_with_keybind(1)
|
|
|
|
assert_int(crono.player_score).is_equal(2)
|
|
assert_bool(_quiz.winner_popup.visible).is_false()
|
|
|
|
|
|
func test_next_shows_the_winner_after_the_last_song() -> void:
|
|
_add_player("Crono")
|
|
_add_player("Marle")
|
|
await _use_folder(_prepared_quiz())
|
|
await _play_first_song()
|
|
await _give_point_with_keybind(2)
|
|
await _play_whole_quiz_rest()
|
|
|
|
var next_button: Button = _quiz.get_node("SongControls/NextButton")
|
|
assert_str(next_button.text).is_equal("Show winner")
|
|
assert_bool(next_button.disabled).is_false()
|
|
next_button.pressed.emit()
|
|
|
|
assert_bool(_quiz.winner_popup.visible).is_true()
|
|
assert_str(_quiz.winner_popup.winner_label.text).is_equal("Marle won with 1 point!!")
|
|
|
|
|
|
func _play_whole_quiz_rest() -> void:
|
|
for i: int in 2:
|
|
await _next()
|
|
|
|
|
|
func test_tied_players_all_win() -> void:
|
|
_add_player("Crono")
|
|
_add_player("Marle")
|
|
_add_player("Lucca")
|
|
await _use_folder(_prepared_quiz())
|
|
await _play_first_song()
|
|
await _give_point_with_keybind(1)
|
|
await _give_point_with_keybind(3)
|
|
await _play_whole_quiz_rest()
|
|
|
|
_press("SongControls/NextButton")
|
|
|
|
assert_str(_quiz.winner_popup.winner_label.text).is_equal("Crono and Lucca won with 1 point!!")
|
|
var header: Node = _quiz.winner_popup.winner_picture.get_parent()
|
|
var pictures: Array = header.get_children().filter(
|
|
func(node: Node) -> bool: return node is TextureRect && node.visible)
|
|
assert_array(pictures).has_size(2)
|
|
var others: Array = _quiz.winner_popup.players_list.get_children().map(
|
|
func(label: Label) -> String: return label.text)
|
|
assert_array(others).contains_exactly(["3. Marle - 0 points"])
|
|
|
|
|
|
func test_new_game_turns_show_winner_back_into_next() -> void:
|
|
await _use_folder(_prepared_quiz())
|
|
await _play_whole_quiz()
|
|
|
|
_press("QuizToolbar/ResetPlaylistButton")
|
|
await _runner.simulate_frames(2)
|
|
|
|
var next_button: Button = _quiz.get_node("SongControls/NextButton")
|
|
assert_str(next_button.text).is_equal("Next song")
|
|
await _play_first_song()
|
|
assert_str(Playlist.song_object_array[Playlist.currently_playing_song].song_title) \
|
|
.is_equal("01. Opening")
|
|
|
|
|
|
func test_songs_playing_on_by_themselves_stop_at_the_end() -> void:
|
|
await _use_folder(_prepared_quiz())
|
|
await _play_whole_quiz()
|
|
|
|
_quiz.play_next_song()
|
|
await _runner.simulate_frames(2)
|
|
|
|
assert_str(Playlist.song_object_array[Playlist.currently_playing_song].song_title) \
|
|
.is_equal("10. Banjo Tooie - Cloud Race")
|
|
assert_str((_quiz.get_node("SongControls/NextButton") as Button).text) \
|
|
.is_equal("Show winner")
|
|
|
|
|
|
func test_quiz_settings_hide_the_winning_score_for_a_prepared_quiz() -> void:
|
|
await _use_folder(_prepared_quiz())
|
|
|
|
_quiz.quiz_settings_card.open()
|
|
|
|
assert_bool(_quiz.quiz_settings_card.winning_score_row.visible).is_false()
|