Indent every script with tabs, like the Godot editor does
This commit is contained in:
1 parent
8c1987807c
commit
bad4b3ad8b
35 files changed
+1653
-1653
No files matched your search
+22
-22
@@ -12,31 +12,31 @@ var _owner: Node
|
|||||||
|
|
||||||
|
|
||||||
func _init(owner: Node) -> void:
|
func _init(owner: Node) -> void:
|
||||||
_owner = owner
|
_owner = owner
|
||||||
|
|
||||||
|
|
||||||
## Requests [param url] and calls [param on_complete] with
|
## Requests [param url] and calls [param on_complete] with
|
||||||
## [code](response_code: int, body: PackedByteArray)[/code]. Connection errors and
|
## [code](response_code: int, body: PackedByteArray)[/code]. Connection errors and
|
||||||
## timeouts are reported with response code 0.
|
## timeouts are reported with response code 0.
|
||||||
func request(url: String, method: int, on_complete: Callable) -> void:
|
func request(url: String, method: int, on_complete: Callable) -> void:
|
||||||
var http_request: HTTPRequest = HTTPRequest.new()
|
var http_request: HTTPRequest = HTTPRequest.new()
|
||||||
http_request.timeout = timeout_seconds
|
http_request.timeout = timeout_seconds
|
||||||
_owner.add_child(http_request)
|
_owner.add_child(http_request)
|
||||||
http_request.request_completed.connect(
|
http_request.request_completed.connect(
|
||||||
func(
|
func(
|
||||||
result: int,
|
result: int,
|
||||||
response_code: int,
|
response_code: int,
|
||||||
_headers: PackedStringArray,
|
_headers: PackedStringArray,
|
||||||
body: PackedByteArray,
|
body: PackedByteArray,
|
||||||
) -> void:
|
) -> void:
|
||||||
http_request.queue_free()
|
http_request.queue_free()
|
||||||
on_complete.call(response_code if result == HTTPRequest.RESULT_SUCCESS else 0, body)
|
on_complete.call(response_code if result == HTTPRequest.RESULT_SUCCESS else 0, body)
|
||||||
)
|
)
|
||||||
var headers: PackedStringArray = []
|
var headers: PackedStringArray = []
|
||||||
if method == HTTPClient.METHOD_PUT:
|
if method == HTTPClient.METHOD_PUT:
|
||||||
headers.append("Content-Type: application/json")
|
headers.append("Content-Type: application/json")
|
||||||
var error: int = http_request.request(url, headers, method)
|
var error: int = http_request.request(url, headers, method)
|
||||||
if error != OK:
|
if error != OK:
|
||||||
http_request.queue_free()
|
http_request.queue_free()
|
||||||
push_error("Could not send request to %s (error %d)" % [url, error])
|
push_error("Could not send request to %s (error %d)" % [url, error])
|
||||||
on_complete.call(0, PackedByteArray())
|
on_complete.call(0, PackedByteArray())
|
||||||
+36
-36
@@ -14,54 +14,54 @@ var _rows: VBoxContainer = $VBoxContainer
|
|||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
scroll_direction = 1
|
scroll_direction = 1
|
||||||
|
|
||||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
var speed_pixels_per_second: float = float(Settings.inspiration_list_speed) * 60.0
|
var speed_pixels_per_second: float = float(Settings.inspiration_list_speed) * 60.0
|
||||||
var scroll_amount: float = speed_pixels_per_second * delta * float(scroll_direction)
|
var scroll_amount: float = speed_pixels_per_second * delta * float(scroll_direction)
|
||||||
|
|
||||||
var scroll_bar = get_v_scroll_bar()
|
var scroll_bar = get_v_scroll_bar()
|
||||||
|
|
||||||
# Don't scroll if list is empty or too short
|
# Don't scroll if list is empty or too short
|
||||||
if scroll_bar.max_value <= 0:
|
if scroll_bar.max_value <= 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
var current_pos = scroll_bar.value
|
var current_pos = scroll_bar.value
|
||||||
|
|
||||||
if scroll_direction == 1:
|
if scroll_direction == 1:
|
||||||
# Scrolling down
|
# Scrolling down
|
||||||
if current_pos + scroll_bar.page < scroll_bar.max_value:
|
if current_pos + scroll_bar.page < scroll_bar.max_value:
|
||||||
scroll_bar.value = min(current_pos + scroll_amount, scroll_bar.max_value - scroll_bar.page)
|
scroll_bar.value = min(current_pos + scroll_amount, scroll_bar.max_value - scroll_bar.page)
|
||||||
else:
|
else:
|
||||||
# Reached bottom, reverse direction
|
# Reached bottom, reverse direction
|
||||||
scroll_direction = -1
|
scroll_direction = -1
|
||||||
scroll_bar.value = scroll_bar.max_value - scroll_bar.page
|
scroll_bar.value = scroll_bar.max_value - scroll_bar.page
|
||||||
else:
|
else:
|
||||||
# Scrolling up
|
# Scrolling up
|
||||||
if current_pos > 0:
|
if current_pos > 0:
|
||||||
scroll_bar.value = max(current_pos + scroll_amount, 0)
|
scroll_bar.value = max(current_pos + scroll_amount, 0)
|
||||||
else:
|
else:
|
||||||
# Reached top, reverse direction
|
# Reached top, reverse direction
|
||||||
scroll_direction = 1
|
scroll_direction = 1
|
||||||
scroll_bar.value = 0
|
scroll_bar.value = 0
|
||||||
|
|
||||||
|
|
||||||
## Fetches every soundtrack from the server and shows them.
|
## Fetches every soundtrack from the server and shows them.
|
||||||
func load_from_server() -> void:
|
func load_from_server() -> void:
|
||||||
print("load_from_server")
|
print("load_from_server")
|
||||||
var populate_list: Callable = func populate_list(array) -> void:
|
var populate_list: Callable = func populate_list(array) -> void:
|
||||||
if typeof(array) == TYPE_ARRAY:
|
if typeof(array) == TYPE_ARRAY:
|
||||||
show_soundtracks(array)
|
show_soundtracks(array)
|
||||||
else:
|
else:
|
||||||
print("Unexpected data")
|
print("Unexpected data")
|
||||||
MusicServerClient.fetch_all_soundtracks(populate_list)
|
MusicServerClient.fetch_all_soundtracks(populate_list)
|
||||||
|
|
||||||
|
|
||||||
## Shows [param list] instead of the soundtracks shown now.
|
## Shows [param list] instead of the soundtracks shown now.
|
||||||
func show_soundtracks(list: Array) -> void:
|
func show_soundtracks(list: Array) -> void:
|
||||||
soundtracks = []
|
soundtracks = []
|
||||||
soundtracks.append_array(list)
|
soundtracks.append_array(list)
|
||||||
Settings.delete_children(_rows)
|
Settings.delete_children(_rows)
|
||||||
for i: int in soundtracks.size():
|
for i: int in soundtracks.size():
|
||||||
_rows.add_child(ListRow.create(soundtracks[i], i, 20))
|
_rows.add_child(ListRow.create(soundtracks[i], i, 20))
|
||||||
+17
-17
@@ -5,20 +5,20 @@ extends SceneTree
|
|||||||
|
|
||||||
|
|
||||||
func _initialize() -> void:
|
func _initialize() -> void:
|
||||||
var args: PackedStringArray = OS.get_cmdline_user_args()
|
var args: PackedStringArray = OS.get_cmdline_user_args()
|
||||||
if args.size() != 3:
|
if args.size() != 3:
|
||||||
printerr("Usage: godot --headless -s render_icon.gd -- <input.svg> <output.png> <size>")
|
printerr("Usage: godot --headless -s render_icon.gd -- <input.svg> <output.png> <size>")
|
||||||
quit(1)
|
quit(1)
|
||||||
return
|
return
|
||||||
var svg: String = FileAccess.get_file_as_string(args[0])
|
var svg: String = FileAccess.get_file_as_string(args[0])
|
||||||
var source: Image = Image.new()
|
var source: Image = Image.new()
|
||||||
# Load at 1x to read the SVG's own size, then scale so the result is <size> pixels
|
# Load at 1x to read the SVG's own size, then scale so the result is <size> pixels
|
||||||
var error: int = source.load_svg_from_string(svg)
|
var error: int = source.load_svg_from_string(svg)
|
||||||
if error == OK:
|
if error == OK:
|
||||||
var image: Image = Image.new()
|
var image: Image = Image.new()
|
||||||
error = image.load_svg_from_string(svg, float(args[2]) / source.get_width())
|
error = image.load_svg_from_string(svg, float(args[2]) / source.get_width())
|
||||||
if error == OK:
|
if error == OK:
|
||||||
error = image.save_png(args[1])
|
error = image.save_png(args[1])
|
||||||
if error != OK:
|
if error != OK:
|
||||||
printerr("Could not render %s to %s (error %d)" % [args[0], args[1], error])
|
printerr("Could not render %s to %s (error %d)" % [args[0], args[1], error])
|
||||||
quit(error)
|
quit(error)
|
||||||
+27
-27
@@ -16,42 +16,42 @@ var label: Label
|
|||||||
|
|
||||||
## The item's text.
|
## The item's text.
|
||||||
var text: String:
|
var text: String:
|
||||||
get:
|
get:
|
||||||
return label.text
|
return label.text
|
||||||
|
|
||||||
|
|
||||||
## Creates the row for item number [param row] (counting from 0) in a list.
|
## Creates the row for item number [param row] (counting from 0) in a list.
|
||||||
static func create(
|
static func create(
|
||||||
item_text: String,
|
item_text: String,
|
||||||
row: int,
|
row: int,
|
||||||
font_size: int,
|
font_size: int,
|
||||||
alignment: HorizontalAlignment = HORIZONTAL_ALIGNMENT_LEFT,
|
alignment: HorizontalAlignment = HORIZONTAL_ALIGNMENT_LEFT,
|
||||||
) -> ListRow:
|
) -> ListRow:
|
||||||
var list_row: ListRow = ListRow.new()
|
var list_row: ListRow = ListRow.new()
|
||||||
list_row.add_theme_stylebox_override("panel", _style(row % 2 != 0))
|
list_row.add_theme_stylebox_override("panel", _style(row % 2 != 0))
|
||||||
list_row.label = Label.new()
|
list_row.label = Label.new()
|
||||||
list_row.label.add_theme_font_size_override("font_size", font_size)
|
list_row.label.add_theme_font_size_override("font_size", font_size)
|
||||||
list_row.label.text = item_text
|
list_row.label.text = item_text
|
||||||
list_row.label.horizontal_alignment = alignment
|
list_row.label.horizontal_alignment = alignment
|
||||||
list_row.label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
list_row.label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||||
list_row.add_child(list_row.label)
|
list_row.add_child(list_row.label)
|
||||||
return list_row
|
return list_row
|
||||||
|
|
||||||
|
|
||||||
# Rows share two styles instead of each creating its own
|
# Rows share two styles instead of each creating its own
|
||||||
static func _style(odd: bool) -> StyleBoxFlat:
|
static func _style(odd: bool) -> StyleBoxFlat:
|
||||||
if _even_style == null:
|
if _even_style == null:
|
||||||
_even_style = _make_style(EVEN_BACKGROUND)
|
_even_style = _make_style(EVEN_BACKGROUND)
|
||||||
_odd_style = _make_style(ODD_BACKGROUND)
|
_odd_style = _make_style(ODD_BACKGROUND)
|
||||||
return _odd_style if odd else _even_style
|
return _odd_style if odd else _even_style
|
||||||
|
|
||||||
|
|
||||||
static func _make_style(background: Color) -> StyleBoxFlat:
|
static func _make_style(background: Color) -> StyleBoxFlat:
|
||||||
var style: StyleBoxFlat = StyleBoxFlat.new()
|
var style: StyleBoxFlat = StyleBoxFlat.new()
|
||||||
style.bg_color = background
|
style.bg_color = background
|
||||||
style.set_corner_radius_all(4)
|
style.set_corner_radius_all(4)
|
||||||
style.content_margin_left = 8
|
style.content_margin_left = 8
|
||||||
style.content_margin_right = 8
|
style.content_margin_right = 8
|
||||||
style.content_margin_top = 2
|
style.content_margin_top = 2
|
||||||
style.content_margin_bottom = 2
|
style.content_margin_bottom = 2
|
||||||
return style
|
return style
|
||||||
+8
-8
@@ -13,14 +13,14 @@ var _rows: VBoxContainer = $ScrollContainer/MusicList
|
|||||||
|
|
||||||
## Shows the songs in the playlist again, so it shows their latest state.
|
## Shows the songs in the playlist again, so it shows their latest state.
|
||||||
func refresh() -> void:
|
func refresh() -> void:
|
||||||
Settings.delete_children(_rows)
|
Settings.delete_children(_rows)
|
||||||
for s: SongObject in Playlist.get_playlist():
|
for s: SongObject in Playlist.get_playlist():
|
||||||
var new_song_list_object: SongListObject = _song_list_object.instantiate()
|
var new_song_list_object: SongListObject = _song_list_object.instantiate()
|
||||||
new_song_list_object.song_object = s
|
new_song_list_object.song_object = s
|
||||||
new_song_list_object.gui_input.connect(_on_row_input.bind(s.song_number))
|
new_song_list_object.gui_input.connect(_on_row_input.bind(s.song_number))
|
||||||
_rows.add_child(new_song_list_object)
|
_rows.add_child(new_song_list_object)
|
||||||
|
|
||||||
|
|
||||||
func _on_row_input(event: InputEvent, song_no: int) -> void:
|
func _on_row_input(event: InputEvent, song_no: int) -> void:
|
||||||
if event is InputEventMouseButton && event.pressed && event.button_index == MOUSE_BUTTON_LEFT:
|
if event is InputEventMouseButton && event.pressed && event.button_index == MOUSE_BUTTON_LEFT:
|
||||||
song_clicked.emit(song_no)
|
song_clicked.emit(song_no)
|
||||||
+44
-44
@@ -11,129 +11,129 @@ var transport: HttpTransport
|
|||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
if transport == null:
|
if transport == null:
|
||||||
transport = HttpTransport.new(self)
|
transport = HttpTransport.new(self)
|
||||||
|
|
||||||
|
|
||||||
## Fetches the songs already in the server playlist, as an Array of
|
## Fetches the songs already in the server playlist, as an Array of
|
||||||
## [code]{SongNo, Soundtrack, Song}[/code] dictionaries.
|
## [code]{SongNo, Soundtrack, Song}[/code] dictionaries.
|
||||||
func fetch_song_list(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
func fetch_song_list(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
||||||
get_json("/music/list", on_done, on_failed)
|
get_json("/music/list", on_done, on_failed)
|
||||||
|
|
||||||
|
|
||||||
## Downloads a random song as MP3 bytes. With [param low_played] the server prefers
|
## Downloads a random song as MP3 bytes. With [param low_played] the server prefers
|
||||||
## soundtracks that have been played the least.
|
## soundtracks that have been played the least.
|
||||||
func fetch_random_song(
|
func fetch_random_song(
|
||||||
low_played: bool, on_done: Callable, on_failed: Callable = Callable()) -> void:
|
low_played: bool, on_done: Callable, on_failed: Callable = Callable()) -> void:
|
||||||
get_bytes("/music/rand/low" if low_played else "/music/rand", on_done, on_failed)
|
get_bytes("/music/rand/low" if low_played else "/music/rand", on_done, on_failed)
|
||||||
|
|
||||||
|
|
||||||
## Adds the most recently fetched random song to the server playlist.
|
## Adds the most recently fetched random song to the server playlist.
|
||||||
func add_to_queue(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
func add_to_queue(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
||||||
send("/music/addQue", on_done, on_failed)
|
send("/music/addQue", on_done, on_failed)
|
||||||
|
|
||||||
|
|
||||||
## Fetches [code]{SongNo, Soundtrack, Song}[/code] for the most recently queued song.
|
## Fetches [code]{SongNo, Soundtrack, Song}[/code] for the most recently queued song.
|
||||||
func fetch_song_info(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
func fetch_song_info(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
||||||
get_json("/music/info", on_done, on_failed)
|
get_json("/music/info", on_done, on_failed)
|
||||||
|
|
||||||
|
|
||||||
## Downloads a song from the server playlist as MP3 bytes.
|
## Downloads a song from the server playlist as MP3 bytes.
|
||||||
func fetch_song(song_no: int, on_done: Callable, on_failed: Callable = Callable()) -> void:
|
func fetch_song(song_no: int, on_done: Callable, on_failed: Callable = Callable()) -> void:
|
||||||
get_bytes("/music?song=" + str(song_no), on_done, on_failed)
|
get_bytes("/music?song=" + str(song_no), on_done, on_failed)
|
||||||
|
|
||||||
|
|
||||||
## Downloads the sound test song as MP3 bytes.
|
## Downloads the sound test song as MP3 bytes.
|
||||||
func fetch_sound_test_song(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
func fetch_sound_test_song(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
||||||
get_bytes("/music/soundTest", on_done, on_failed)
|
get_bytes("/music/soundTest", on_done, on_failed)
|
||||||
|
|
||||||
|
|
||||||
## Clears the server playlist.
|
## Clears the server playlist.
|
||||||
func reset_playlist(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
func reset_playlist(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
||||||
send("/music/reset", on_done, on_failed)
|
send("/music/reset", on_done, on_failed)
|
||||||
|
|
||||||
|
|
||||||
## Fetches every soundtrack name as an Array of Strings.
|
## Fetches every soundtrack name as an Array of Strings.
|
||||||
func fetch_all_soundtracks(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
func fetch_all_soundtracks(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
||||||
get_json("/music/all", on_done, on_failed)
|
get_json("/music/all", on_done, on_failed)
|
||||||
|
|
||||||
|
|
||||||
## Fetches every soundtrack name, sorted, as an Array of Strings.
|
## Fetches every soundtrack name, sorted, as an Array of Strings.
|
||||||
func fetch_all_soundtracks_ordered(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
func fetch_all_soundtracks_ordered(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
||||||
get_json("/music/all/order", on_done, on_failed)
|
get_json("/music/all/order", on_done, on_failed)
|
||||||
|
|
||||||
|
|
||||||
## Records in the server statistics that a song has been played.
|
## Records in the server statistics that a song has been played.
|
||||||
func mark_song_played(song_no: int) -> void:
|
func mark_song_played(song_no: int) -> void:
|
||||||
send("/music/played?song=" + str(song_no), Callable(), Callable(), HTTPClient.METHOD_PUT)
|
send("/music/played?song=" + str(song_no), Callable(), Callable(), HTTPClient.METHOD_PUT)
|
||||||
|
|
||||||
|
|
||||||
## Fetches the names of all character images.
|
## Fetches the names of all character images.
|
||||||
func fetch_character_list(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
func fetch_character_list(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
||||||
get_json("/characters", on_done, on_failed)
|
get_json("/characters", on_done, on_failed)
|
||||||
|
|
||||||
|
|
||||||
## Downloads a character image as PNG bytes.
|
## Downloads a character image as PNG bytes.
|
||||||
func fetch_character_image(
|
func fetch_character_image(
|
||||||
character_name: String, on_done: Callable, on_failed: Callable = Callable()) -> void:
|
character_name: String, on_done: Callable, on_failed: Callable = Callable()) -> void:
|
||||||
get_bytes("/character?name=" + character_name.uri_encode(), on_done, on_failed)
|
get_bytes("/character?name=" + character_name.uri_encode(), on_done, on_failed)
|
||||||
|
|
||||||
|
|
||||||
## Starts syncing the server's soundtrack library with its music folder.
|
## Starts syncing the server's soundtrack library with its music folder.
|
||||||
func start_sync(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
func start_sync(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
||||||
send("/sync", on_done, on_failed)
|
send("/sync", on_done, on_failed)
|
||||||
|
|
||||||
|
|
||||||
## Fetches the sync state: [code]{progress, time_spent}[/code] while running, or the
|
## Fetches the sync state: [code]{progress, time_spent}[/code] while running, or the
|
||||||
## sync result once finished.
|
## sync result once finished.
|
||||||
func fetch_sync_progress(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
func fetch_sync_progress(on_done: Callable, on_failed: Callable = Callable()) -> void:
|
||||||
get_json("/sync/progress", on_done, on_failed)
|
get_json("/sync/progress", on_done, on_failed)
|
||||||
|
|
||||||
|
|
||||||
## Requests [param path] and calls [param on_done] with the parsed JSON.
|
## Requests [param path] and calls [param on_done] with the parsed JSON.
|
||||||
## [param on_failed] is called with no arguments if the request fails or the body is
|
## [param on_failed] is called with no arguments if the request fails or the body is
|
||||||
## not valid JSON.
|
## not valid JSON.
|
||||||
func get_json(path: String, on_done: Callable, on_failed: Callable = Callable()) -> void:
|
func get_json(path: String, on_done: Callable, on_failed: Callable = Callable()) -> void:
|
||||||
_request(path, HTTPClient.METHOD_GET, func(body: PackedByteArray) -> void:
|
_request(path, HTTPClient.METHOD_GET, func(body: PackedByteArray) -> void:
|
||||||
var json: JSON = JSON.new()
|
var json: JSON = JSON.new()
|
||||||
if json.parse(body.get_string_from_utf8()) != OK:
|
if json.parse(body.get_string_from_utf8()) != OK:
|
||||||
push_warning("Invalid JSON from %s: %s" % [path, json.get_error_message()])
|
push_warning("Invalid JSON from %s: %s" % [path, json.get_error_message()])
|
||||||
_call_if_valid(on_failed)
|
_call_if_valid(on_failed)
|
||||||
return
|
return
|
||||||
on_done.call(json.data)
|
on_done.call(json.data)
|
||||||
, on_failed)
|
, on_failed)
|
||||||
|
|
||||||
|
|
||||||
## Requests [param path] and calls [param on_done] with the raw response body, or
|
## Requests [param path] and calls [param on_done] with the raw response body, or
|
||||||
## [param on_failed] with no arguments if the request fails.
|
## [param on_failed] with no arguments if the request fails.
|
||||||
func get_bytes(path: String, on_done: Callable, on_failed: Callable = Callable()) -> void:
|
func get_bytes(path: String, on_done: Callable, on_failed: Callable = Callable()) -> void:
|
||||||
_request(path, HTTPClient.METHOD_GET, on_done, on_failed)
|
_request(path, HTTPClient.METHOD_GET, on_done, on_failed)
|
||||||
|
|
||||||
|
|
||||||
## Requests [param path] and calls [param on_done] with no arguments when it succeeds,
|
## Requests [param path] and calls [param on_done] with no arguments when it succeeds,
|
||||||
## or [param on_failed] when it fails. Either may be an empty Callable.
|
## or [param on_failed] when it fails. Either may be an empty Callable.
|
||||||
func send(
|
func send(
|
||||||
path: String,
|
path: String,
|
||||||
on_done: Callable,
|
on_done: Callable,
|
||||||
on_failed: Callable = Callable(),
|
on_failed: Callable = Callable(),
|
||||||
method: int = HTTPClient.METHOD_GET,
|
method: int = HTTPClient.METHOD_GET,
|
||||||
) -> void:
|
) -> void:
|
||||||
_request(path, method, func(_body: PackedByteArray) -> void:
|
_request(path, method, func(_body: PackedByteArray) -> void:
|
||||||
_call_if_valid(on_done)
|
_call_if_valid(on_done)
|
||||||
, on_failed)
|
, on_failed)
|
||||||
|
|
||||||
|
|
||||||
func _request(path: String, method: int, on_success: Callable, on_failed: Callable) -> void:
|
func _request(path: String, method: int, on_success: Callable, on_failed: Callable) -> void:
|
||||||
var url: String = Settings.default_path + path
|
var url: String = Settings.default_path + path
|
||||||
transport.request(url, method, func(response_code: int, body: PackedByteArray) -> void:
|
transport.request(url, method, func(response_code: int, body: PackedByteArray) -> void:
|
||||||
if response_code != 200:
|
if response_code != 200:
|
||||||
push_warning("Request to %s failed with response code %d" % [url, response_code])
|
push_warning("Request to %s failed with response code %d" % [url, response_code])
|
||||||
_call_if_valid(on_failed)
|
_call_if_valid(on_failed)
|
||||||
return
|
return
|
||||||
on_success.call(body)
|
on_success.call(body)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
static func _call_if_valid(callback: Callable) -> void:
|
static func _call_if_valid(callback: Callable) -> void:
|
||||||
if callback.is_valid():
|
if callback.is_valid():
|
||||||
callback.call()
|
callback.call()
|
||||||
+31
-31
@@ -34,57 +34,57 @@ var players_list_container: VBoxContainer = $VBoxContainer/ScrollContainer/Playe
|
|||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
add_players_button.pressed.connect(add_players)
|
add_players_button.pressed.connect(add_players)
|
||||||
add_player_button.pressed.connect(add_player)
|
add_player_button.pressed.connect(add_player)
|
||||||
new_player_name_field.connect("enter_key_pressed", add_player)
|
new_player_name_field.connect("enter_key_pressed", add_player)
|
||||||
|
|
||||||
|
|
||||||
## Shows or hides the row for adding players, and the buttons for removing them.
|
## Shows or hides the row for adding players, and the buttons for removing them.
|
||||||
func add_players() -> void:
|
func add_players() -> void:
|
||||||
print("add_players")
|
print("add_players")
|
||||||
Settings.edit_players = !Settings.edit_players
|
Settings.edit_players = !Settings.edit_players
|
||||||
add_player_container.visible = !add_player_container.visible
|
add_player_container.visible = !add_player_container.visible
|
||||||
new_player_name_field.grab_focus()
|
new_player_name_field.grab_focus()
|
||||||
|
|
||||||
|
|
||||||
## Adds a player with the name in the name field, unless it is empty or there are
|
## Adds a player with the name in the name field, unless it is empty or there are
|
||||||
## already as many players as there can be.
|
## already as many players as there can be.
|
||||||
func add_player() -> void:
|
func add_player() -> void:
|
||||||
print("add_player")
|
print("add_player")
|
||||||
if new_player_name_field.text != "" && Settings.player_array.size() < Settings.MAX_NUMBER_OF_PLAYERS:
|
if new_player_name_field.text != "" && Settings.player_array.size() < Settings.MAX_NUMBER_OF_PLAYERS:
|
||||||
var new_player_object: PlayerObject = PlayerObject.new(new_player_name_field.text)
|
var new_player_object: PlayerObject = PlayerObject.new(new_player_name_field.text)
|
||||||
new_player_name_field.text = ""
|
new_player_name_field.text = ""
|
||||||
Settings.player_array.append(new_player_object)
|
Settings.player_array.append(new_player_object)
|
||||||
player_added.emit(new_player_object)
|
player_added.emit(new_player_object)
|
||||||
reload()
|
reload()
|
||||||
|
|
||||||
|
|
||||||
## Shows the players in [code]Settings.player_array[/code] again, e.g. after their
|
## Shows the players in [code]Settings.player_array[/code] again, e.g. after their
|
||||||
## points were reset.
|
## points were reset.
|
||||||
func reload() -> void:
|
func reload() -> void:
|
||||||
print("load_players")
|
print("load_players")
|
||||||
Settings.delete_children(players_list_container)
|
Settings.delete_children(players_list_container)
|
||||||
var counter: int = 0
|
var counter: int = 0
|
||||||
for player_object: PlayerObject in Settings.player_array:
|
for player_object: PlayerObject in Settings.player_array:
|
||||||
print(player_object.player_name)
|
print(player_object.player_name)
|
||||||
|
|
||||||
var new_player: Player = _player_row.instantiate()
|
var new_player: Player = _player_row.instantiate()
|
||||||
new_player.player_object = player_object
|
new_player.player_object = player_object
|
||||||
new_player.list_index = counter
|
new_player.list_index = counter
|
||||||
|
|
||||||
new_player.connect("change_character_clicked", _on_change_character_clicked.bind(new_player, player_object.player_name))
|
new_player.connect("change_character_clicked", _on_change_character_clicked.bind(new_player, player_object.player_name))
|
||||||
new_player.connect("player_removed", _on_player_removed.bind(player_object))
|
new_player.connect("player_removed", _on_player_removed.bind(player_object))
|
||||||
|
|
||||||
players_list_container.add_child(new_player)
|
players_list_container.add_child(new_player)
|
||||||
counter += 1
|
counter += 1
|
||||||
|
|
||||||
|
|
||||||
func _on_change_character_clicked(row: Player, player_name: String) -> void:
|
func _on_change_character_clicked(row: Player, player_name: String) -> void:
|
||||||
change_character_requested.emit(row, player_name)
|
change_character_requested.emit(row, player_name)
|
||||||
|
|
||||||
|
|
||||||
func _on_player_removed(player_object: PlayerObject) -> void:
|
func _on_player_removed(player_object: PlayerObject) -> void:
|
||||||
print("_on_player_removed ", player_object.player_name)
|
print("_on_player_removed ", player_object.player_name)
|
||||||
Settings.player_array.erase(player_object)
|
Settings.player_array.erase(player_object)
|
||||||
reload()
|
reload()
|
||||||
player_removed.emit(player_object)
|
player_removed.emit(player_object)
|
||||||
+13
-13
@@ -13,19 +13,19 @@ var _popups: Array[PopupWindow] = []
|
|||||||
## Adds a backdrop to [param parent] and moves [param popups] above it. The backdrop
|
## Adds a backdrop to [param parent] and moves [param popups] above it. The backdrop
|
||||||
## shows while any of them is open.
|
## shows while any of them is open.
|
||||||
static func add_to(parent: Control, popups: Array[PopupWindow]) -> PopupBackdrop:
|
static func add_to(parent: Control, popups: Array[PopupWindow]) -> PopupBackdrop:
|
||||||
var backdrop: PopupBackdrop = PopupBackdrop.new()
|
var backdrop: PopupBackdrop = PopupBackdrop.new()
|
||||||
backdrop.name = "PopupBackdrop"
|
backdrop.name = "PopupBackdrop"
|
||||||
backdrop.color = Color(0, 0, 0, 0.55)
|
backdrop.color = Color(0, 0, 0, 0.55)
|
||||||
backdrop.mouse_filter = Control.MOUSE_FILTER_STOP
|
backdrop.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||||
backdrop._popups = popups
|
backdrop._popups = popups
|
||||||
parent.add_child(backdrop)
|
parent.add_child(backdrop)
|
||||||
backdrop.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
backdrop.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||||
for popup: PopupWindow in popups:
|
for popup: PopupWindow in popups:
|
||||||
parent.move_child(popup, -1)
|
parent.move_child(popup, -1)
|
||||||
popup.visibility_changed.connect(backdrop._update)
|
popup.visibility_changed.connect(backdrop._update)
|
||||||
backdrop._update()
|
backdrop._update()
|
||||||
return backdrop
|
return backdrop
|
||||||
|
|
||||||
|
|
||||||
func _update() -> void:
|
func _update() -> void:
|
||||||
visible = _popups.any(func(popup: PopupWindow) -> bool: return popup.visible)
|
visible = _popups.any(func(popup: PopupWindow) -> bool: return popup.visible)
|
||||||
+13
-13
@@ -11,27 +11,27 @@ extends Control
|
|||||||
|
|
||||||
## Shows the popup.
|
## Shows the popup.
|
||||||
func open() -> void:
|
func open() -> void:
|
||||||
visible = true
|
visible = true
|
||||||
|
|
||||||
|
|
||||||
## Hides the popup.
|
## Hides the popup.
|
||||||
func close() -> void:
|
func close() -> void:
|
||||||
visible = false
|
visible = false
|
||||||
|
|
||||||
|
|
||||||
## Opens the popup if it is closed and closes it if it is open.
|
## Opens the popup if it is closed and closes it if it is open.
|
||||||
func toggle() -> void:
|
func toggle() -> void:
|
||||||
if visible:
|
if visible:
|
||||||
close()
|
close()
|
||||||
else:
|
else:
|
||||||
open()
|
open()
|
||||||
|
|
||||||
|
|
||||||
func _input(event: InputEvent) -> void:
|
func _input(event: InputEvent) -> void:
|
||||||
if !visible || !(event is InputEventMouseButton) || !event.pressed:
|
if !visible || !(event is InputEventMouseButton) || !event.pressed:
|
||||||
return
|
return
|
||||||
var click: InputEventMouseButton = panel.make_input_local(event)
|
var click: InputEventMouseButton = panel.make_input_local(event)
|
||||||
if !Rect2(Vector2.ZERO, panel.size).has_point(click.position):
|
if !Rect2(Vector2.ZERO, panel.size).has_point(click.position):
|
||||||
close()
|
close()
|
||||||
# The click only closes the popup; it must not also press what is behind it
|
# The click only closes the popup; it must not also press what is behind it
|
||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
@@ -8,20 +8,20 @@ var _values: Dictionary = {}
|
|||||||
|
|
||||||
## Records the current values of every script variable on [param autoloads].
|
## Records the current values of every script variable on [param autoloads].
|
||||||
static func take(autoloads: Array[Node]) -> AutoloadSnapshot:
|
static func take(autoloads: Array[Node]) -> AutoloadSnapshot:
|
||||||
var snapshot: AutoloadSnapshot = AutoloadSnapshot.new()
|
var snapshot: AutoloadSnapshot = AutoloadSnapshot.new()
|
||||||
for autoload: Node in autoloads:
|
for autoload: Node in autoloads:
|
||||||
var values: Dictionary = {}
|
var values: Dictionary = {}
|
||||||
for property: Dictionary in autoload.get_property_list():
|
for property: Dictionary in autoload.get_property_list():
|
||||||
if property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE:
|
if property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE:
|
||||||
var value: Variant = autoload.get(property.name)
|
var value: Variant = autoload.get(property.name)
|
||||||
values[property.name] = value.duplicate() if value is Array else value
|
values[property.name] = value.duplicate() if value is Array else value
|
||||||
snapshot._values[autoload] = values
|
snapshot._values[autoload] = values
|
||||||
return snapshot
|
return snapshot
|
||||||
|
|
||||||
|
|
||||||
## Puts back the values recorded by [method take].
|
## Puts back the values recorded by [method take].
|
||||||
func restore() -> void:
|
func restore() -> void:
|
||||||
for autoload: Node in _values:
|
for autoload: Node in _values:
|
||||||
var values: Dictionary = _values[autoload]
|
var values: Dictionary = _values[autoload]
|
||||||
for property_name: String in values:
|
for property_name: String in values:
|
||||||
autoload.set(property_name, values[property_name])
|
autoload.set(property_name, values[property_name])
|
||||||
@@ -18,74 +18,74 @@ var _previous_transport: HttpTransport
|
|||||||
|
|
||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
super(null)
|
super(null)
|
||||||
|
|
||||||
|
|
||||||
## Replaces the MusicServerClient transport with this fake.
|
## Replaces the MusicServerClient transport with this fake.
|
||||||
func install() -> FakeHttpTransport:
|
func install() -> FakeHttpTransport:
|
||||||
_previous_transport = MusicServerClient.transport
|
_previous_transport = MusicServerClient.transport
|
||||||
MusicServerClient.transport = self
|
MusicServerClient.transport = self
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
## Restores the transport that was active before [method install].
|
## Restores the transport that was active before [method install].
|
||||||
func uninstall() -> void:
|
func uninstall() -> void:
|
||||||
MusicServerClient.transport = _previous_transport
|
MusicServerClient.transport = _previous_transport
|
||||||
|
|
||||||
|
|
||||||
## Answers requests to [param path] with [param data] encoded as JSON.
|
## Answers requests to [param path] with [param data] encoded as JSON.
|
||||||
func respond_json(path: String, data: Variant, response_code: int = 200) -> void:
|
func respond_json(path: String, data: Variant, response_code: int = 200) -> void:
|
||||||
respond_bytes(path, JSON.stringify(data).to_utf8_buffer(), response_code)
|
respond_bytes(path, JSON.stringify(data).to_utf8_buffer(), response_code)
|
||||||
|
|
||||||
|
|
||||||
## Answers requests to [param path] with [param body] as-is.
|
## Answers requests to [param path] with [param body] as-is.
|
||||||
func respond_bytes(path: String, body: PackedByteArray, response_code: int = 200) -> void:
|
func respond_bytes(path: String, body: PackedByteArray, response_code: int = 200) -> void:
|
||||||
_responses[path] = {"code": response_code, "body": body}
|
_responses[path] = {"code": response_code, "body": body}
|
||||||
_successes_left.erase(path)
|
_successes_left.erase(path)
|
||||||
|
|
||||||
|
|
||||||
## Lets [param successes] more requests to [param path] succeed, then answers 503 until
|
## Lets [param successes] more requests to [param path] succeed, then answers 503 until
|
||||||
## a new response is registered for the path.
|
## a new response is registered for the path.
|
||||||
func fail_after(path: String, successes: int) -> void:
|
func fail_after(path: String, successes: int) -> void:
|
||||||
_successes_left[path] = successes
|
_successes_left[path] = successes
|
||||||
|
|
||||||
|
|
||||||
## Holds back responses to [param path] until [method release] is called, like a slow
|
## Holds back responses to [param path] until [method release] is called, like a slow
|
||||||
## server.
|
## server.
|
||||||
func hold(path: String) -> void:
|
func hold(path: String) -> void:
|
||||||
_held_paths[path] = []
|
_held_paths[path] = []
|
||||||
|
|
||||||
|
|
||||||
## Delivers the responses held back for [param path] and stops holding it.
|
## Delivers the responses held back for [param path] and stops holding it.
|
||||||
func release(path: String) -> void:
|
func release(path: String) -> void:
|
||||||
var waiting: Array = _held_paths.get(path, [])
|
var waiting: Array = _held_paths.get(path, [])
|
||||||
_held_paths.erase(path)
|
_held_paths.erase(path)
|
||||||
for pending: Callable in waiting:
|
for pending: Callable in waiting:
|
||||||
pending.call()
|
pending.call()
|
||||||
|
|
||||||
|
|
||||||
## Returns how many times [param path] has been requested.
|
## Returns how many times [param path] has been requested.
|
||||||
func count(path: String) -> int:
|
func count(path: String) -> int:
|
||||||
return requested_paths.count(path)
|
return requested_paths.count(path)
|
||||||
|
|
||||||
|
|
||||||
func request(url: String, method: int, on_complete: Callable) -> void:
|
func request(url: String, method: int, on_complete: Callable) -> void:
|
||||||
var path: String = url.trim_prefix(Settings.default_path)
|
var path: String = url.trim_prefix(Settings.default_path)
|
||||||
requested_paths.append(path)
|
requested_paths.append(path)
|
||||||
requested_methods.append(method)
|
requested_methods.append(method)
|
||||||
if _held_paths.has(path):
|
if _held_paths.has(path):
|
||||||
_held_paths[path].append(_answer.bind(path, on_complete))
|
_held_paths[path].append(_answer.bind(path, on_complete))
|
||||||
return
|
return
|
||||||
_answer(path, on_complete)
|
_answer(path, on_complete)
|
||||||
|
|
||||||
|
|
||||||
func _answer(path: String, on_complete: Callable) -> void:
|
func _answer(path: String, on_complete: Callable) -> void:
|
||||||
if _successes_left.has(path):
|
if _successes_left.has(path):
|
||||||
if _successes_left[path] == 0:
|
if _successes_left[path] == 0:
|
||||||
on_complete.call(503, PackedByteArray())
|
on_complete.call(503, PackedByteArray())
|
||||||
return
|
return
|
||||||
_successes_left[path] -= 1
|
_successes_left[path] -= 1
|
||||||
if _responses.has(path):
|
if _responses.has(path):
|
||||||
on_complete.call(_responses[path].code, _responses[path].body)
|
on_complete.call(_responses[path].code, _responses[path].body)
|
||||||
else:
|
else:
|
||||||
on_complete.call(404, PackedByteArray())
|
on_complete.call(404, PackedByteArray())
|
||||||
@@ -3,8 +3,8 @@ extends GdUnitTestSuite
|
|||||||
## Base for tests that run the real main window against a fake MusicServer.
|
## Base for tests that run the real main window against a fake MusicServer.
|
||||||
|
|
||||||
const SONG_INFO: Array[Dictionary] = [
|
const SONG_INFO: Array[Dictionary] = [
|
||||||
{"SongNo": 0, "Soundtrack": "Chrono Trigger", "Song": "Corridors of Time"},
|
{"SongNo": 0, "Soundtrack": "Chrono Trigger", "Song": "Corridors of Time"},
|
||||||
{"SongNo": 1, "Soundtrack": "Final Fantasy VI", "Song": "Dancing Mad"},
|
{"SongNo": 1, "Soundtrack": "Final Fantasy VI", "Song": "Dancing Mad"},
|
||||||
]
|
]
|
||||||
|
|
||||||
var _server: FakeHttpTransport
|
var _server: FakeHttpTransport
|
||||||
@@ -15,120 +15,120 @@ var _quiz: Quiz
|
|||||||
|
|
||||||
|
|
||||||
func before_test() -> void:
|
func before_test() -> void:
|
||||||
_snapshot = AutoloadSnapshot.take([Settings, Playlist])
|
_snapshot = AutoloadSnapshot.take([Settings, Playlist])
|
||||||
Playlist.reset_playlist()
|
Playlist.reset_playlist()
|
||||||
Playlist.first_song_played = false
|
Playlist.first_song_played = false
|
||||||
Playlist.is_song_downloading = false
|
Playlist.is_song_downloading = false
|
||||||
Settings.player_array.clear()
|
Settings.player_array.clear()
|
||||||
Settings.add_to_stats = true
|
Settings.add_to_stats = true
|
||||||
Settings.hide_next_track = true
|
Settings.hide_next_track = true
|
||||||
Settings.use_low_played_mode = false
|
Settings.use_low_played_mode = false
|
||||||
Settings.winning_score = 20
|
Settings.winning_score = 20
|
||||||
|
|
||||||
_server = FakeHttpTransport.new().install()
|
_server = FakeHttpTransport.new().install()
|
||||||
var mp3: PackedByteArray = FileAccess.get_file_as_bytes("res://tests/data/short.mp3")
|
var mp3: PackedByteArray = FileAccess.get_file_as_bytes("res://tests/data/short.mp3")
|
||||||
_server.respond_json("/music/all", ["Chrono Trigger", "Final Fantasy VI"])
|
_server.respond_json("/music/all", ["Chrono Trigger", "Final Fantasy VI"])
|
||||||
_server.respond_json("/music/all/order", ["Chrono Trigger", "Final Fantasy VI"])
|
_server.respond_json("/music/all/order", ["Chrono Trigger", "Final Fantasy VI"])
|
||||||
_server.respond_json("/music/list", [])
|
_server.respond_json("/music/list", [])
|
||||||
_server.respond_json("/characters", [])
|
_server.respond_json("/characters", [])
|
||||||
_server.respond_bytes("/music/rand", mp3)
|
_server.respond_bytes("/music/rand", mp3)
|
||||||
_server.respond_bytes("/music/addQue", PackedByteArray())
|
_server.respond_bytes("/music/addQue", PackedByteArray())
|
||||||
_server.respond_json("/music/info", SONG_INFO[0])
|
_server.respond_json("/music/info", SONG_INFO[0])
|
||||||
_server.respond_bytes("/music/reset", PackedByteArray())
|
_server.respond_bytes("/music/reset", PackedByteArray())
|
||||||
_server.respond_bytes("/music/played?song=0", PackedByteArray())
|
_server.respond_bytes("/music/played?song=0", PackedByteArray())
|
||||||
|
|
||||||
_before_window_starts()
|
_before_window_starts()
|
||||||
_runner = scene_runner("res://MainWindow.tscn")
|
_runner = scene_runner("res://MainWindow.tscn")
|
||||||
_window = _runner.scene()
|
_window = _runner.scene()
|
||||||
_quiz = _window.get_node("Quiz")
|
_quiz = _window.get_node("Quiz")
|
||||||
# The debug build lowers the winning score on startup; keep it out of reach
|
# The debug build lowers the winning score on startup; keep it out of reach
|
||||||
Settings.winning_score = 20
|
Settings.winning_score = 20
|
||||||
|
|
||||||
|
|
||||||
## Override to change the fake server before the window starts and sends its first
|
## Override to change the fake server before the window starts and sends its first
|
||||||
## requests.
|
## requests.
|
||||||
func _before_window_starts() -> void:
|
func _before_window_starts() -> void:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
func after_test() -> void:
|
func after_test() -> void:
|
||||||
# Let nodes queued for deletion by the window be freed before orphans are counted
|
# Let nodes queued for deletion by the window be freed before orphans are counted
|
||||||
await await_idle_frame()
|
await await_idle_frame()
|
||||||
_server.uninstall()
|
_server.uninstall()
|
||||||
_snapshot.restore()
|
_snapshot.restore()
|
||||||
|
|
||||||
|
|
||||||
## Makes the next song the server hands out the one described by [param info].
|
## Makes the next song the server hands out the one described by [param info].
|
||||||
func _next_song_is(info: Dictionary) -> void:
|
func _next_song_is(info: Dictionary) -> void:
|
||||||
_server.respond_json("/music/info", info)
|
_server.respond_json("/music/info", info)
|
||||||
|
|
||||||
|
|
||||||
## Presses a button in the quiz.
|
## Presses a button in the quiz.
|
||||||
func _press(button_path: String) -> void:
|
func _press(button_path: String) -> void:
|
||||||
(_quiz.get_node(button_path) as Button).pressed.emit()
|
(_quiz.get_node(button_path) as Button).pressed.emit()
|
||||||
|
|
||||||
|
|
||||||
## Presses Next and waits until the first song is playing.
|
## Presses Next and waits until the first song is playing.
|
||||||
func _play_first_song() -> void:
|
func _play_first_song() -> void:
|
||||||
_press("NextButton")
|
_press("NextButton")
|
||||||
await _runner.simulate_frames(2)
|
await _runner.simulate_frames(2)
|
||||||
|
|
||||||
|
|
||||||
## Adds a player through the name field, the same way the user does.
|
## Adds a player through the name field, the same way the user does.
|
||||||
func _add_player(player_name: String) -> PlayerObject:
|
func _add_player(player_name: String) -> PlayerObject:
|
||||||
var name_field: TextEdit = _quiz.get_node(
|
var name_field: TextEdit = _quiz.get_node(
|
||||||
"PlayersPanel/VBoxContainer/AddPlayerContainer/PlayerNameField")
|
"PlayersPanel/VBoxContainer/AddPlayerContainer/PlayerNameField")
|
||||||
name_field.text = player_name
|
name_field.text = player_name
|
||||||
_quiz.players_panel.add_player()
|
_quiz.players_panel.add_player()
|
||||||
return Settings.player_array.back() if !Settings.player_array.is_empty() else null
|
return Settings.player_array.back() if !Settings.player_array.is_empty() else null
|
||||||
|
|
||||||
|
|
||||||
## Returns the row in the player list that shows [param player_object].
|
## Returns the row in the player list that shows [param player_object].
|
||||||
func _player_row(player_object: PlayerObject) -> Player:
|
func _player_row(player_object: PlayerObject) -> Player:
|
||||||
var rows: Node = _quiz.get_node(
|
var rows: Node = _quiz.get_node(
|
||||||
"PlayersPanel/VBoxContainer/ScrollContainer/PlayersListVBoxContainer")
|
"PlayersPanel/VBoxContainer/ScrollContainer/PlayersListVBoxContainer")
|
||||||
for row: Player in rows.get_children():
|
for row: Player in rows.get_children():
|
||||||
if row.player_object == player_object:
|
if row.player_object == player_object:
|
||||||
return row
|
return row
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
|
||||||
## Removes a player with the remove button in its row.
|
## Removes a player with the remove button in its row.
|
||||||
func _remove_player(player_object: PlayerObject) -> void:
|
func _remove_player(player_object: PlayerObject) -> void:
|
||||||
(_player_row(player_object).get_node("HBoxContainer/RemovePlayer") as BaseButton) \
|
(_player_row(player_object).get_node("HBoxContainer/RemovePlayer") as BaseButton) \
|
||||||
.pressed.emit()
|
.pressed.emit()
|
||||||
await _runner.simulate_frames(1)
|
await _runner.simulate_frames(1)
|
||||||
|
|
||||||
|
|
||||||
## Clicks at [param position], given in the window's 1920x1080 layout coordinates.
|
## Clicks at [param position], given in the window's 1920x1080 layout coordinates.
|
||||||
func _click_at(position: Vector2) -> void:
|
func _click_at(position: Vector2) -> void:
|
||||||
# The runner takes window pixels; the headless test window is much smaller than the
|
# The runner takes window pixels; the headless test window is much smaller than the
|
||||||
# layout, so convert like a real mouse position would be
|
# layout, so convert like a real mouse position would be
|
||||||
_runner.set_mouse_position(_window.get_viewport().get_final_transform() * position)
|
_runner.set_mouse_position(_window.get_viewport().get_final_transform() * position)
|
||||||
await _runner.simulate_mouse_button_pressed(MOUSE_BUTTON_LEFT)
|
await _runner.simulate_mouse_button_pressed(MOUSE_BUTTON_LEFT)
|
||||||
await _runner.await_input_processed()
|
await _runner.await_input_processed()
|
||||||
|
|
||||||
|
|
||||||
## Presses [param keys] together, e.g. [code][KEY_ALT, KEY_1][/code], then releases them.
|
## Presses [param keys] together, e.g. [code][KEY_ALT, KEY_1][/code], then releases them.
|
||||||
func _press_keys(keys: Array[Key]) -> void:
|
func _press_keys(keys: Array[Key]) -> void:
|
||||||
for key: Key in keys:
|
for key: Key in keys:
|
||||||
_runner.simulate_key_press(key)
|
_runner.simulate_key_press(key)
|
||||||
await _runner.await_input_processed()
|
await _runner.await_input_processed()
|
||||||
keys.reverse()
|
keys.reverse()
|
||||||
for key: Key in keys:
|
for key: Key in keys:
|
||||||
_runner.simulate_key_release(key)
|
_runner.simulate_key_release(key)
|
||||||
await _runner.await_input_processed()
|
await _runner.await_input_processed()
|
||||||
|
|
||||||
|
|
||||||
## Gives a point with Alt+<number>.
|
## Gives a point with Alt+<number>.
|
||||||
func _give_point_with_keybind(number: int) -> void:
|
func _give_point_with_keybind(number: int) -> void:
|
||||||
await _press_keys([KEY_ALT, (KEY_0 + number) as Key])
|
await _press_keys([KEY_ALT, (KEY_0 + number) as Key])
|
||||||
|
|
||||||
|
|
||||||
## Takes a point with Ctrl+Alt+<number>.
|
## Takes a point with Ctrl+Alt+<number>.
|
||||||
func _take_point_with_keybind(number: int) -> void:
|
func _take_point_with_keybind(number: int) -> void:
|
||||||
await _press_keys([KEY_CTRL, KEY_ALT, (KEY_0 + number) as Key])
|
await _press_keys([KEY_CTRL, KEY_ALT, (KEY_0 + number) as Key])
|
||||||
|
|
||||||
|
|
||||||
func _scores() -> Array:
|
func _scores() -> Array:
|
||||||
return Settings.player_array.map(func(p: PlayerObject) -> int: return p.player_score)
|
return Settings.player_array.map(func(p: PlayerObject) -> int: return p.player_score)
|
||||||
+153
-153
@@ -9,131 +9,131 @@ extends RefCounted
|
|||||||
## them a node lives in.
|
## them a node lives in.
|
||||||
|
|
||||||
const SOUNDTRACKS: Array[String] = [
|
const SOUNDTRACKS: Array[String] = [
|
||||||
"Chrono Trigger", "Final Fantasy VI", "Secret of Mana", "Terranigma",
|
"Chrono Trigger", "Final Fantasy VI", "Secret of Mana", "Terranigma",
|
||||||
"Earthbound", "Super Metroid", "The Legend of Zelda: A Link to the Past",
|
"Earthbound", "Super Metroid", "The Legend of Zelda: A Link to the Past",
|
||||||
"Donkey Kong Country 2", "Lufia II", "Illusion of Gaia",
|
"Donkey Kong Country 2", "Lufia II", "Illusion of Gaia",
|
||||||
]
|
]
|
||||||
const SONG_INFO: Dictionary = {
|
const SONG_INFO: Dictionary = {
|
||||||
"SongNo": 0, "Soundtrack": "Chrono Trigger", "Song": "Corridors of Time",
|
"SongNo": 0, "Soundtrack": "Chrono Trigger", "Song": "Corridors of Time",
|
||||||
}
|
}
|
||||||
const SYNC_PROGRESS: Dictionary = {"progress": 40, "time_spent": "00:00:02"}
|
const SYNC_PROGRESS: Dictionary = {"progress": 40, "time_spent": "00:00:02"}
|
||||||
const SYNC_RESULT: Dictionary = {
|
const SYNC_RESULT: Dictionary = {
|
||||||
"soundtracks_added": ["Terranigma", "Lufia II"],
|
"soundtracks_added": ["Terranigma", "Lufia II"],
|
||||||
"soundtracks_re_added": [],
|
"soundtracks_re_added": [],
|
||||||
"soundtracks_changed_title": {"FF6": "Final Fantasy VI"},
|
"soundtracks_changed_title": {"FF6": "Final Fantasy VI"},
|
||||||
"soundtracks_changed_content": ["Chrono Trigger"],
|
"soundtracks_changed_content": ["Chrono Trigger"],
|
||||||
"soundtracks_removed": ["Old Soundtrack"],
|
"soundtracks_removed": ["Old Soundtrack"],
|
||||||
"catched_errors": [],
|
"catched_errors": [],
|
||||||
"total_time": "00:00:03",
|
"total_time": "00:00:03",
|
||||||
}
|
}
|
||||||
|
|
||||||
## Popups in the order the tour opens them.
|
## Popups in the order the tour opens them.
|
||||||
const POPUPS: Array[String] = [
|
const POPUPS: Array[String] = [
|
||||||
"Search", "SyncWindow", "SettingsWindow", "QRWindow", "NewCharacterSelect",
|
"Search", "SyncWindow", "SettingsWindow", "QRWindow", "NewCharacterSelect",
|
||||||
"ShortcutsWindow", "AboutWindow", "WinnerWindow", "Log", "StatisticsPopupPanel",
|
"ShortcutsWindow", "AboutWindow", "WinnerWindow", "Log", "StatisticsPopupPanel",
|
||||||
]
|
]
|
||||||
|
|
||||||
var _main: Control
|
var _main: Control
|
||||||
|
|
||||||
|
|
||||||
func _init(main: Control) -> void:
|
func _init(main: Control) -> void:
|
||||||
_main = main
|
_main = main
|
||||||
|
|
||||||
|
|
||||||
## Returns a fake server that answers every request the main window makes on the tour.
|
## Returns a fake server that answers every request the main window makes on the tour.
|
||||||
## Call [method FakeHttpTransport.install] before the main window is created.
|
## Call [method FakeHttpTransport.install] before the main window is created.
|
||||||
static func make_server() -> FakeHttpTransport:
|
static func make_server() -> FakeHttpTransport:
|
||||||
var server: FakeHttpTransport = FakeHttpTransport.new()
|
var server: FakeHttpTransport = FakeHttpTransport.new()
|
||||||
var mp3: PackedByteArray = FileAccess.get_file_as_bytes("res://tests/data/short.mp3")
|
var mp3: PackedByteArray = FileAccess.get_file_as_bytes("res://tests/data/short.mp3")
|
||||||
server.respond_json("/music/all", SOUNDTRACKS)
|
server.respond_json("/music/all", SOUNDTRACKS)
|
||||||
server.respond_json("/music/all/order", SOUNDTRACKS)
|
server.respond_json("/music/all/order", SOUNDTRACKS)
|
||||||
server.respond_json("/music/list", [])
|
server.respond_json("/music/list", [])
|
||||||
server.respond_json("/characters", [])
|
server.respond_json("/characters", [])
|
||||||
server.respond_bytes("/music/rand", mp3)
|
server.respond_bytes("/music/rand", mp3)
|
||||||
server.respond_bytes("/music/addQue", PackedByteArray())
|
server.respond_bytes("/music/addQue", PackedByteArray())
|
||||||
server.respond_json("/music/info", SONG_INFO)
|
server.respond_json("/music/info", SONG_INFO)
|
||||||
server.respond_bytes("/music/reset", PackedByteArray())
|
server.respond_bytes("/music/reset", PackedByteArray())
|
||||||
server.respond_bytes("/music/played?song=0", PackedByteArray())
|
server.respond_bytes("/music/played?song=0", PackedByteArray())
|
||||||
server.respond_bytes("/sync", PackedByteArray())
|
server.respond_bytes("/sync", PackedByteArray())
|
||||||
server.respond_json("/sync/progress", SYNC_PROGRESS)
|
server.respond_json("/sync/progress", SYNC_PROGRESS)
|
||||||
return server
|
return server
|
||||||
|
|
||||||
|
|
||||||
## Puts Settings and Playlist in the state the tour expects. Call it before the main
|
## Puts Settings and Playlist in the state the tour expects. Call it before the main
|
||||||
## window is created.
|
## window is created.
|
||||||
static func prepare_autoloads() -> void:
|
static func prepare_autoloads() -> void:
|
||||||
Playlist.reset_playlist()
|
Playlist.reset_playlist()
|
||||||
Playlist.first_song_played = false
|
Playlist.first_song_played = false
|
||||||
Playlist.is_song_downloading = false
|
Playlist.is_song_downloading = false
|
||||||
Settings.player_array.clear()
|
Settings.player_array.clear()
|
||||||
Settings.edit_players = false
|
Settings.edit_players = false
|
||||||
Settings.currently_syncing = false
|
Settings.currently_syncing = false
|
||||||
Settings.character_select_open = false
|
Settings.character_select_open = false
|
||||||
Settings.add_to_stats = true
|
Settings.add_to_stats = true
|
||||||
Settings.hide_next_track = true
|
Settings.hide_next_track = true
|
||||||
Settings.use_low_played_mode = false
|
Settings.use_low_played_mode = false
|
||||||
Settings.winning_score = 20
|
Settings.winning_score = 20
|
||||||
# The inspiration list scrolls by itself, which would make every picture different
|
# The inspiration list scrolls by itself, which would make every picture different
|
||||||
Settings.inspiration_list_speed = 0
|
Settings.inspiration_list_speed = 0
|
||||||
|
|
||||||
|
|
||||||
## Runs the tour. [param on_state] is called (and awaited) with the name of each state
|
## Runs the tour. [param on_state] is called (and awaited) with the name of each state
|
||||||
## and the popup that is open in it, or [code]null[/code] when no popup is open.
|
## and the popup that is open in it, or [code]null[/code] when no popup is open.
|
||||||
func run(on_state: Callable) -> void:
|
func run(on_state: Callable) -> void:
|
||||||
# The debug build lowers the winning score on startup; keep it out of reach
|
# The debug build lowers the winning score on startup; keep it out of reach
|
||||||
Settings.winning_score = 20
|
Settings.winning_score = 20
|
||||||
await _settle()
|
await _settle()
|
||||||
await on_state.call("startup", null)
|
await on_state.call("startup", null)
|
||||||
|
|
||||||
_call("add_players")
|
_call("add_players")
|
||||||
await _settle()
|
await _settle()
|
||||||
await on_state.call("add_player_row", null)
|
await on_state.call("add_player_row", null)
|
||||||
|
|
||||||
_add_player("Crono")
|
_add_player("Crono")
|
||||||
_add_player("Marle")
|
_add_player("Marle")
|
||||||
_call("add_players")
|
_call("add_players")
|
||||||
await _settle()
|
await _settle()
|
||||||
await on_state.call("players_added", null)
|
await on_state.call("players_added", null)
|
||||||
|
|
||||||
_call("play_next_song")
|
_call("play_next_song")
|
||||||
await _settle()
|
await _settle()
|
||||||
_freeze_music_player()
|
_freeze_music_player()
|
||||||
_player_row(0).add_point()
|
_player_row(0).add_point()
|
||||||
_player_row(0).add_point()
|
_player_row(0).add_point()
|
||||||
_player_row(1).add_point()
|
_player_row(1).add_point()
|
||||||
_call("show_answer_pressed")
|
_call("show_answer_pressed")
|
||||||
await _settle()
|
await _settle()
|
||||||
_freeze_music_player()
|
_freeze_music_player()
|
||||||
_fix_log_times()
|
_fix_log_times()
|
||||||
await _settle()
|
await _settle()
|
||||||
await on_state.call("playing", null)
|
await on_state.call("playing", null)
|
||||||
|
|
||||||
for popup_name: String in POPUPS:
|
for popup_name: String in POPUPS:
|
||||||
var popup: Node = await _open_popup(popup_name)
|
var popup: Node = await _open_popup(popup_name)
|
||||||
await _settle()
|
await _settle()
|
||||||
await on_state.call("popup_" + popup_name, popup)
|
await on_state.call("popup_" + popup_name, popup)
|
||||||
_close_popup(popup)
|
_close_popup(popup)
|
||||||
await _settle()
|
await _settle()
|
||||||
|
|
||||||
var sync_window: PopupWindow = _node("SyncWindow")
|
var sync_window: PopupWindow = _node("SyncWindow")
|
||||||
Settings.currently_syncing = false
|
Settings.currently_syncing = false
|
||||||
sync_window.has_synced = false
|
sync_window.has_synced = false
|
||||||
sync_window.start_sync()
|
sync_window.start_sync()
|
||||||
sync_window.sync_timer.stop()
|
sync_window.sync_timer.stop()
|
||||||
sync_window._on_sync_timeout()
|
sync_window._on_sync_timeout()
|
||||||
await _settle()
|
await _settle()
|
||||||
await on_state.call("sync_in_progress", sync_window)
|
await on_state.call("sync_in_progress", sync_window)
|
||||||
sync_window.close()
|
sync_window.close()
|
||||||
await _settle()
|
await _settle()
|
||||||
await on_state.call("sync_buttons_locked", null)
|
await on_state.call("sync_buttons_locked", null)
|
||||||
|
|
||||||
_server().respond_json("/sync/progress", SYNC_RESULT)
|
_server().respond_json("/sync/progress", SYNC_RESULT)
|
||||||
sync_window._on_sync_timeout()
|
sync_window._on_sync_timeout()
|
||||||
sync_window.open()
|
sync_window.open()
|
||||||
await _settle()
|
await _settle()
|
||||||
await on_state.call("sync_result", sync_window)
|
await on_state.call("sync_result", sync_window)
|
||||||
sync_window.close()
|
sync_window.close()
|
||||||
await _settle()
|
await _settle()
|
||||||
|
|
||||||
|
|
||||||
## Returns where every Control and Window in [param subtree] is on screen, keyed by its
|
## Returns where every Control and Window in [param subtree] is on screen, keyed by its
|
||||||
@@ -141,109 +141,109 @@ func run(on_state: Callable) -> void:
|
|||||||
## Nodes added at runtime without a name are keyed by their index, e.g. [code]#2[/code],
|
## Nodes added at runtime without a name are keyed by their index, e.g. [code]#2[/code],
|
||||||
## so the keys are the same on every run.
|
## so the keys are the same on every run.
|
||||||
static func dump_layout(main: Node, subtree: Node) -> Dictionary:
|
static func dump_layout(main: Node, subtree: Node) -> Dictionary:
|
||||||
var layout: Dictionary = {}
|
var layout: Dictionary = {}
|
||||||
var path: String = String(main.get_path_to(subtree))
|
var path: String = String(main.get_path_to(subtree))
|
||||||
_dump_node(subtree, path, layout)
|
_dump_node(subtree, path, layout)
|
||||||
return layout
|
return layout
|
||||||
|
|
||||||
|
|
||||||
static func _dump_node(node: Node, path: String, layout: Dictionary) -> void:
|
static func _dump_node(node: Node, path: String, layout: Dictionary) -> void:
|
||||||
if node is Control:
|
if node is Control:
|
||||||
var rect: Rect2 = (node as Control).get_global_rect()
|
var rect: Rect2 = (node as Control).get_global_rect()
|
||||||
layout[path] = {"rect": _round_rect(rect), "visible": node.is_visible_in_tree()}
|
layout[path] = {"rect": _round_rect(rect), "visible": node.is_visible_in_tree()}
|
||||||
elif node is Window:
|
elif node is Window:
|
||||||
var window: Window = node
|
var window: Window = node
|
||||||
layout[path] = {
|
layout[path] = {
|
||||||
"rect": _round_rect(Rect2(window.position, window.size)),
|
"rect": _round_rect(Rect2(window.position, window.size)),
|
||||||
"visible": window.visible,
|
"visible": window.visible,
|
||||||
}
|
}
|
||||||
for child: Node in node.get_children():
|
for child: Node in node.get_children():
|
||||||
var key: String = "#%d" % child.get_index() if "@" in child.name \
|
var key: String = "#%d" % child.get_index() if "@" in child.name \
|
||||||
else String(child.name)
|
else String(child.name)
|
||||||
_dump_node(child, key if path == "." else path + "/" + key, layout)
|
_dump_node(child, key if path == "." else path + "/" + key, layout)
|
||||||
|
|
||||||
|
|
||||||
static func _round_rect(rect: Rect2) -> Array[float]:
|
static func _round_rect(rect: Rect2) -> Array[float]:
|
||||||
return [snappedf(rect.position.x, 0.01), snappedf(rect.position.y, 0.01),
|
return [snappedf(rect.position.x, 0.01), snappedf(rect.position.y, 0.01),
|
||||||
snappedf(rect.size.x, 0.01), snappedf(rect.size.y, 0.01)]
|
snappedf(rect.size.x, 0.01), snappedf(rect.size.y, 0.01)]
|
||||||
|
|
||||||
|
|
||||||
## Finds a node of the main window by [param node_name], whether it is a direct child
|
## Finds a node of the main window by [param node_name], whether it is a direct child
|
||||||
## of the main window or of its Quiz or TopBar scene.
|
## of the main window or of its Quiz or TopBar scene.
|
||||||
func _node(node_name: String) -> Node:
|
func _node(node_name: String) -> Node:
|
||||||
for parent: Node in [_main, _main.get_node_or_null("Quiz"),
|
for parent: Node in [_main, _main.get_node_or_null("Quiz"),
|
||||||
_main.get_node_or_null("TopBar")]:
|
_main.get_node_or_null("TopBar")]:
|
||||||
if parent != null && parent.has_node(node_name):
|
if parent != null && parent.has_node(node_name):
|
||||||
return parent.get_node(node_name)
|
return parent.get_node(node_name)
|
||||||
push_error("UiTour: no node named " + node_name)
|
push_error("UiTour: no node named " + node_name)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
|
||||||
## Calls [param method] on the players panel, the quiz or the main window, whichever
|
## Calls [param method] on the players panel, the quiz or the main window, whichever
|
||||||
## has it first.
|
## has it first.
|
||||||
func _call(method: String, args: Array = []) -> Variant:
|
func _call(method: String, args: Array = []) -> Variant:
|
||||||
for path: String in ["Quiz/PlayersPanel", "Quiz"]:
|
for path: String in ["Quiz/PlayersPanel", "Quiz"]:
|
||||||
var target: Node = _main.get_node_or_null(path)
|
var target: Node = _main.get_node_or_null(path)
|
||||||
if target != null && target.has_method(method):
|
if target != null && target.has_method(method):
|
||||||
return target.callv(method, args)
|
return target.callv(method, args)
|
||||||
return _main.callv(method, args)
|
return _main.callv(method, args)
|
||||||
|
|
||||||
|
|
||||||
func _server() -> FakeHttpTransport:
|
func _server() -> FakeHttpTransport:
|
||||||
return MusicServerClient.transport
|
return MusicServerClient.transport
|
||||||
|
|
||||||
|
|
||||||
func _settle() -> void:
|
func _settle() -> void:
|
||||||
for i: int in 4:
|
for i: int in 4:
|
||||||
await _main.get_tree().process_frame
|
await _main.get_tree().process_frame
|
||||||
|
|
||||||
|
|
||||||
func _add_player(player_name: String) -> void:
|
func _add_player(player_name: String) -> void:
|
||||||
(_node("PlayersPanel").get_node("VBoxContainer/AddPlayerContainer/PlayerNameField") \
|
(_node("PlayersPanel").get_node("VBoxContainer/AddPlayerContainer/PlayerNameField") \
|
||||||
as TextEdit).text = player_name
|
as TextEdit).text = player_name
|
||||||
_call("add_player")
|
_call("add_player")
|
||||||
|
|
||||||
|
|
||||||
func _player_row(index: int) -> Player:
|
func _player_row(index: int) -> Player:
|
||||||
return _node("PlayersPanel").get_node(
|
return _node("PlayersPanel").get_node(
|
||||||
"VBoxContainer/ScrollContainer/PlayersListVBoxContainer").get_child(index)
|
"VBoxContainer/ScrollContainer/PlayersListVBoxContainer").get_child(index)
|
||||||
|
|
||||||
|
|
||||||
## Stops the song so the time and progress bar look the same on every run.
|
## Stops the song so the time and progress bar look the same on every run.
|
||||||
func _freeze_music_player() -> void:
|
func _freeze_music_player() -> void:
|
||||||
var music_player: MusicPlayer = _node("MusicPlayer")
|
var music_player: MusicPlayer = _node("MusicPlayer")
|
||||||
music_player.audio_player.stop()
|
music_player.audio_player.stop()
|
||||||
music_player.sound_player.stop()
|
music_player.sound_player.stop()
|
||||||
music_player.progress_slider.value = 0
|
music_player.progress_slider.value = 0
|
||||||
music_player.music_time_label.text = "00:00 / 00:01"
|
music_player.music_time_label.text = "00:00 / 00:01"
|
||||||
|
|
||||||
|
|
||||||
## The log starts each row with the time of day; use a fixed time instead.
|
## The log starts each row with the time of day; use a fixed time instead.
|
||||||
func _fix_log_times() -> void:
|
func _fix_log_times() -> void:
|
||||||
var log_window: PopupWindow = _node("Log")
|
var log_window: PopupWindow = _node("Log")
|
||||||
for row: Label in log_window.log_box.get_children():
|
for row: Label in log_window.log_box.get_children():
|
||||||
row.text = "12:00:00 " + row.text.substr(9)
|
row.text = "12:00:00 " + row.text.substr(9)
|
||||||
|
|
||||||
|
|
||||||
func _open_popup(popup_name: String) -> Node:
|
func _open_popup(popup_name: String) -> Node:
|
||||||
var popup: Node = _node(popup_name)
|
var popup: Node = _node(popup_name)
|
||||||
match popup_name:
|
match popup_name:
|
||||||
"SyncWindow":
|
"SyncWindow":
|
||||||
# Opening the window starts a sync; show the empty window instead
|
# Opening the window starts a sync; show the empty window instead
|
||||||
popup.open()
|
popup.open()
|
||||||
"NewCharacterSelect":
|
"NewCharacterSelect":
|
||||||
popup.show_grid("Crono")
|
popup.show_grid("Crono")
|
||||||
"WinnerWindow":
|
"WinnerWindow":
|
||||||
popup.show_winner(Settings.player_array[0])
|
popup.show_winner(Settings.player_array[0])
|
||||||
"StatisticsPopupPanel":
|
"StatisticsPopupPanel":
|
||||||
_call("get_statistics")
|
_call("get_statistics")
|
||||||
_:
|
_:
|
||||||
popup.open()
|
popup.open()
|
||||||
return popup
|
return popup
|
||||||
|
|
||||||
|
|
||||||
func _close_popup(popup: Node) -> void:
|
func _close_popup(popup: Node) -> void:
|
||||||
if popup is PopupWindow:
|
if popup is PopupWindow:
|
||||||
popup.close()
|
popup.close()
|
||||||
else:
|
else:
|
||||||
popup.visible = false
|
popup.visible = false
|
||||||
@@ -11,82 +11,82 @@ var _list: InspirationList
|
|||||||
|
|
||||||
|
|
||||||
func before_test() -> void:
|
func before_test() -> void:
|
||||||
_snapshot = AutoloadSnapshot.take([Settings])
|
_snapshot = AutoloadSnapshot.take([Settings])
|
||||||
Settings.inspiration_list_speed = 0
|
Settings.inspiration_list_speed = 0
|
||||||
_server = FakeHttpTransport.new().install()
|
_server = FakeHttpTransport.new().install()
|
||||||
_server.respond_json("/music/all", SOUNDTRACKS)
|
_server.respond_json("/music/all", SOUNDTRACKS)
|
||||||
_runner = scene_runner("res://InspirationList.tscn")
|
_runner = scene_runner("res://InspirationList.tscn")
|
||||||
_list = _runner.scene()
|
_list = _runner.scene()
|
||||||
|
|
||||||
|
|
||||||
func after_test() -> void:
|
func after_test() -> void:
|
||||||
await await_idle_frame()
|
await await_idle_frame()
|
||||||
_server.uninstall()
|
_server.uninstall()
|
||||||
_snapshot.restore()
|
_snapshot.restore()
|
||||||
|
|
||||||
|
|
||||||
func _rows() -> Array[Node]:
|
func _rows() -> Array[Node]:
|
||||||
return _list.get_node("VBoxContainer").get_children()
|
return _list.get_node("VBoxContainer").get_children()
|
||||||
|
|
||||||
|
|
||||||
func _texts() -> Array:
|
func _texts() -> Array:
|
||||||
return _rows().map(func(row: ListRow) -> String: return row.text)
|
return _rows().map(func(row: ListRow) -> String: return row.text)
|
||||||
|
|
||||||
|
|
||||||
func test_load_from_server_shows_every_soundtrack_in_order() -> void:
|
func test_load_from_server_shows_every_soundtrack_in_order() -> void:
|
||||||
_list.load_from_server()
|
_list.load_from_server()
|
||||||
|
|
||||||
assert_array(_texts()).contains_exactly(SOUNDTRACKS)
|
assert_array(_texts()).contains_exactly(SOUNDTRACKS)
|
||||||
assert_array(_list.soundtracks).contains_exactly(SOUNDTRACKS)
|
assert_array(_list.soundtracks).contains_exactly(SOUNDTRACKS)
|
||||||
|
|
||||||
|
|
||||||
func test_rows_alternate_backgrounds() -> void:
|
func test_rows_alternate_backgrounds() -> void:
|
||||||
_list.load_from_server()
|
_list.load_from_server()
|
||||||
|
|
||||||
var rows: Array[Node] = _rows()
|
var rows: Array[Node] = _rows()
|
||||||
assert_that((rows[0] as ListRow).get_theme_stylebox("panel")) \
|
assert_that((rows[0] as ListRow).get_theme_stylebox("panel")) \
|
||||||
.is_not_equal((rows[1] as ListRow).get_theme_stylebox("panel"))
|
.is_not_equal((rows[1] as ListRow).get_theme_stylebox("panel"))
|
||||||
assert_that((rows[0] as ListRow).get_theme_stylebox("panel")) \
|
assert_that((rows[0] as ListRow).get_theme_stylebox("panel")) \
|
||||||
.is_equal((rows[2] as ListRow).get_theme_stylebox("panel"))
|
.is_equal((rows[2] as ListRow).get_theme_stylebox("panel"))
|
||||||
|
|
||||||
|
|
||||||
func test_loading_again_replaces_the_rows() -> void:
|
func test_loading_again_replaces_the_rows() -> void:
|
||||||
_list.load_from_server()
|
_list.load_from_server()
|
||||||
_server.respond_json("/music/all", ["Terranigma"])
|
_server.respond_json("/music/all", ["Terranigma"])
|
||||||
|
|
||||||
_list.load_from_server()
|
_list.load_from_server()
|
||||||
|
|
||||||
assert_array(_texts()).contains_exactly(["Terranigma"])
|
assert_array(_texts()).contains_exactly(["Terranigma"])
|
||||||
|
|
||||||
|
|
||||||
func test_failed_load_keeps_the_rows() -> void:
|
func test_failed_load_keeps_the_rows() -> void:
|
||||||
_list.load_from_server()
|
_list.load_from_server()
|
||||||
_server.respond_bytes("/music/all", PackedByteArray(), 500)
|
_server.respond_bytes("/music/all", PackedByteArray(), 500)
|
||||||
|
|
||||||
_list.load_from_server()
|
_list.load_from_server()
|
||||||
|
|
||||||
assert_array(_texts()).contains_exactly(SOUNDTRACKS)
|
assert_array(_texts()).contains_exactly(SOUNDTRACKS)
|
||||||
|
|
||||||
|
|
||||||
func _long_list() -> Array[String]:
|
func _long_list() -> Array[String]:
|
||||||
var names: Array[String] = []
|
var names: Array[String] = []
|
||||||
for i: int in 40:
|
for i: int in 40:
|
||||||
names.append("Soundtrack %d" % i)
|
names.append("Soundtrack %d" % i)
|
||||||
return names
|
return names
|
||||||
|
|
||||||
|
|
||||||
func test_scrolls_down_by_itself() -> void:
|
func test_scrolls_down_by_itself() -> void:
|
||||||
_list.show_soundtracks(_long_list())
|
_list.show_soundtracks(_long_list())
|
||||||
Settings.inspiration_list_speed = 5
|
Settings.inspiration_list_speed = 5
|
||||||
|
|
||||||
await _runner.simulate_frames(30, 16)
|
await _runner.simulate_frames(30, 16)
|
||||||
|
|
||||||
assert_int(_list.scroll_vertical).is_greater(0)
|
assert_int(_list.scroll_vertical).is_greater(0)
|
||||||
|
|
||||||
|
|
||||||
func test_does_not_scroll_at_speed_zero() -> void:
|
func test_does_not_scroll_at_speed_zero() -> void:
|
||||||
_list.show_soundtracks(_long_list())
|
_list.show_soundtracks(_long_list())
|
||||||
|
|
||||||
await _runner.simulate_frames(30, 16)
|
await _runner.simulate_frames(30, 16)
|
||||||
|
|
||||||
assert_int(_list.scroll_vertical).is_equal(0)
|
assert_int(_list.scroll_vertical).is_equal(0)
|
||||||
@@ -12,22 +12,22 @@ const BASELINE_PATH: String = "res://tests/data/layout_baseline.json"
|
|||||||
|
|
||||||
## Nodes that moved from the main window into the Quiz scene, by their old name.
|
## Nodes that moved from the main window into the Quiz scene, by their old name.
|
||||||
const QUIZ_NODES: Array[String] = [
|
const QUIZ_NODES: Array[String] = [
|
||||||
"Open", "FileDialog", "MusicListPanel", "VBoxContainer",
|
"Open", "FileDialog", "MusicListPanel", "VBoxContainer",
|
||||||
"MusicPlayer", "ResetPlaylistButton", "ResetPointsButton", "SettingsButton",
|
"MusicPlayer", "ResetPlaylistButton", "ResetPointsButton", "SettingsButton",
|
||||||
"SoundTestButton", "ShowAnswerButton", "NextButton", "RepeatSongCheckButton",
|
"SoundTestButton", "ShowAnswerButton", "NextButton", "RepeatSongCheckButton",
|
||||||
"DebugLabel", "SettingsWindow", "NewCharacterSelect", "WinnerWindow", "Log",
|
"DebugLabel", "SettingsWindow", "NewCharacterSelect", "WinnerWindow", "Log",
|
||||||
]
|
]
|
||||||
|
|
||||||
## Nodes that moved into the Quiz scene and were renamed there: old name to new name.
|
## Nodes that moved into the Quiz scene and were renamed there: old name to new name.
|
||||||
const RENAMED_QUIZ_NODES: Dictionary = {
|
const RENAMED_QUIZ_NODES: Dictionary = {
|
||||||
"Players": "PlayersPanel",
|
"Players": "PlayersPanel",
|
||||||
"ScrollContainer": "InspirationList",
|
"ScrollContainer": "InspirationList",
|
||||||
}
|
}
|
||||||
|
|
||||||
## Nodes that moved from the main window into the TopBar scene, by their old name.
|
## Nodes that moved from the main window into the TopBar scene, by their old name.
|
||||||
const TOP_BAR_NODES: Array[String] = [
|
const TOP_BAR_NODES: Array[String] = [
|
||||||
"TopPanelContainer", "Title", "SearchButton", "SyncButton", "StatisticsButton",
|
"TopPanelContainer", "Title", "SearchButton", "SyncButton", "StatisticsButton",
|
||||||
"ShortcutsButton", "AboutButton", "QRButton",
|
"ShortcutsButton", "AboutButton", "QRButton",
|
||||||
]
|
]
|
||||||
|
|
||||||
## How far a node may be from its old place, in pixels.
|
## How far a node may be from its old place, in pixels.
|
||||||
@@ -40,67 +40,67 @@ var _layout: Dictionary = {}
|
|||||||
|
|
||||||
|
|
||||||
func before() -> void:
|
func before() -> void:
|
||||||
_snapshot = AutoloadSnapshot.take([Settings, Playlist])
|
_snapshot = AutoloadSnapshot.take([Settings, Playlist])
|
||||||
UiTour.prepare_autoloads()
|
UiTour.prepare_autoloads()
|
||||||
_server = UiTour.make_server().install()
|
_server = UiTour.make_server().install()
|
||||||
# Laid out at the size the baseline was taken at, like the screenshots
|
# Laid out at the size the baseline was taken at, like the screenshots
|
||||||
var viewport: SubViewport = auto_free(SubViewport.new())
|
var viewport: SubViewport = auto_free(SubViewport.new())
|
||||||
viewport.size = Vector2i(1920, 1080)
|
viewport.size = Vector2i(1920, 1080)
|
||||||
viewport.gui_embed_subwindows = true
|
viewport.gui_embed_subwindows = true
|
||||||
Engine.get_main_loop().root.add_child(viewport)
|
Engine.get_main_loop().root.add_child(viewport)
|
||||||
_main = load("res://MainWindow.tscn").instantiate()
|
_main = load("res://MainWindow.tscn").instantiate()
|
||||||
viewport.add_child(_main)
|
viewport.add_child(_main)
|
||||||
await UiTour.new(_main).run(func(state: String, popup: Node) -> void:
|
await UiTour.new(_main).run(func(state: String, popup: Node) -> void:
|
||||||
_layout[state] = UiTour.dump_layout(_main, _main if popup == null else popup))
|
_layout[state] = UiTour.dump_layout(_main, _main if popup == null else popup))
|
||||||
|
|
||||||
|
|
||||||
func after() -> void:
|
func after() -> void:
|
||||||
_main.free()
|
_main.free()
|
||||||
await Engine.get_main_loop().process_frame
|
await Engine.get_main_loop().process_frame
|
||||||
_server.uninstall()
|
_server.uninstall()
|
||||||
_snapshot.restore()
|
_snapshot.restore()
|
||||||
|
|
||||||
|
|
||||||
## Where the node that used to be at [param old_path] in the main window is now.
|
## Where the node that used to be at [param old_path] in the main window is now.
|
||||||
static func new_path(old_path: String) -> String:
|
static func new_path(old_path: String) -> String:
|
||||||
var first: String = old_path.get_slice("/", 0)
|
var first: String = old_path.get_slice("/", 0)
|
||||||
if first in QUIZ_NODES:
|
if first in QUIZ_NODES:
|
||||||
return "Quiz/" + old_path
|
return "Quiz/" + old_path
|
||||||
if first in RENAMED_QUIZ_NODES:
|
if first in RENAMED_QUIZ_NODES:
|
||||||
return "Quiz/" + RENAMED_QUIZ_NODES[first] + old_path.trim_prefix(first)
|
return "Quiz/" + RENAMED_QUIZ_NODES[first] + old_path.trim_prefix(first)
|
||||||
if first in TOP_BAR_NODES:
|
if first in TOP_BAR_NODES:
|
||||||
return "TopBar/" + old_path
|
return "TopBar/" + old_path
|
||||||
return old_path
|
return old_path
|
||||||
|
|
||||||
|
|
||||||
func _baseline() -> Dictionary:
|
func _baseline() -> Dictionary:
|
||||||
return JSON.parse_string(FileAccess.get_file_as_string(BASELINE_PATH))
|
return JSON.parse_string(FileAccess.get_file_as_string(BASELINE_PATH))
|
||||||
|
|
||||||
|
|
||||||
func test_tour_has_the_same_states_as_the_baseline() -> void:
|
func test_tour_has_the_same_states_as_the_baseline() -> void:
|
||||||
assert_array(_layout.keys()).contains_exactly_in_any_order(_baseline().keys())
|
assert_array(_layout.keys()).contains_exactly_in_any_order(_baseline().keys())
|
||||||
|
|
||||||
|
|
||||||
func test_every_node_is_where_it_was() -> void:
|
func test_every_node_is_where_it_was() -> void:
|
||||||
var problems: Array[String] = []
|
var problems: Array[String] = []
|
||||||
var baseline: Dictionary = _baseline()
|
var baseline: Dictionary = _baseline()
|
||||||
for state: String in baseline:
|
for state: String in baseline:
|
||||||
var actual: Dictionary = _layout.get(state, {})
|
var actual: Dictionary = _layout.get(state, {})
|
||||||
for old_path: String in baseline[state]:
|
for old_path: String in baseline[state]:
|
||||||
var path: String = new_path(old_path)
|
var path: String = new_path(old_path)
|
||||||
var expected: Dictionary = baseline[state][old_path]
|
var expected: Dictionary = baseline[state][old_path]
|
||||||
if !actual.has(path):
|
if !actual.has(path):
|
||||||
problems.append("%s: %s is missing (was %s)" % [state, path, old_path])
|
problems.append("%s: %s is missing (was %s)" % [state, path, old_path])
|
||||||
continue
|
continue
|
||||||
var rect: Array = actual[path].rect
|
var rect: Array = actual[path].rect
|
||||||
for i: int in 4:
|
for i: int in 4:
|
||||||
if absf(rect[i] - expected.rect[i]) > TOLERANCE:
|
if absf(rect[i] - expected.rect[i]) > TOLERANCE:
|
||||||
problems.append("%s: %s is at %s, was %s"
|
problems.append("%s: %s is at %s, was %s"
|
||||||
% [state, path, rect, expected.rect])
|
% [state, path, rect, expected.rect])
|
||||||
break
|
break
|
||||||
if actual[path].visible != expected.visible:
|
if actual[path].visible != expected.visible:
|
||||||
problems.append("%s: %s visible is %s, was %s"
|
problems.append("%s: %s visible is %s, was %s"
|
||||||
% [state, path, actual[path].visible, expected.visible])
|
% [state, path, actual[path].visible, expected.visible])
|
||||||
assert_array(problems).override_failure_message(
|
assert_array(problems).override_failure_message(
|
||||||
"%d nodes moved:\n%s" % [problems.size(), "\n".join(problems.slice(0, 30))]) \
|
"%d nodes moved:\n%s" % [problems.size(), "\n".join(problems.slice(0, 30))]) \
|
||||||
.is_empty()
|
.is_empty()
|
||||||
@@ -3,240 +3,240 @@ extends MainWindowTestSuite
|
|||||||
|
|
||||||
|
|
||||||
func test_startup_loads_soundtracks_and_preloads_a_song() -> void:
|
func test_startup_loads_soundtracks_and_preloads_a_song() -> void:
|
||||||
assert_int(_server.count("/music/list")).is_equal(1)
|
assert_int(_server.count("/music/list")).is_equal(1)
|
||||||
assert_int(_server.count("/music/all")).is_equal(1)
|
assert_int(_server.count("/music/all")).is_equal(1)
|
||||||
assert_array(_server.requested_paths).contains(["/music/rand", "/music/addQue", "/music/info"])
|
assert_array(_server.requested_paths).contains(["/music/rand", "/music/addQue", "/music/info"])
|
||||||
assert_int(Playlist.song_object_array.size()).is_equal(1)
|
assert_int(Playlist.song_object_array.size()).is_equal(1)
|
||||||
assert_bool((_quiz.get_node("NextButton") as Button).disabled).is_false()
|
assert_bool((_quiz.get_node("NextButton") as Button).disabled).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_low_played_mode_fetches_from_low_played_endpoint() -> void:
|
func test_low_played_mode_fetches_from_low_played_endpoint() -> void:
|
||||||
Settings.use_low_played_mode = true
|
Settings.use_low_played_mode = true
|
||||||
_server.respond_bytes(
|
_server.respond_bytes(
|
||||||
"/music/rand/low", FileAccess.get_file_as_bytes("res://tests/data/short.mp3"))
|
"/music/rand/low", FileAccess.get_file_as_bytes("res://tests/data/short.mp3"))
|
||||||
|
|
||||||
_quiz.fetch_song()
|
_quiz.fetch_song()
|
||||||
|
|
||||||
assert_int(_server.count("/music/rand/low")).is_equal(1)
|
assert_int(_server.count("/music/rand/low")).is_equal(1)
|
||||||
|
|
||||||
|
|
||||||
func test_next_plays_preloaded_song_and_fetches_another() -> void:
|
func test_next_plays_preloaded_song_and_fetches_another() -> void:
|
||||||
_next_song_is(SONG_INFO[1])
|
_next_song_is(SONG_INFO[1])
|
||||||
|
|
||||||
_press("NextButton")
|
_press("NextButton")
|
||||||
await _runner.simulate_frames(2)
|
await _runner.simulate_frames(2)
|
||||||
|
|
||||||
assert_int(Playlist.currently_playing_song).is_equal(0)
|
assert_int(Playlist.currently_playing_song).is_equal(0)
|
||||||
assert_bool(Playlist.song_object_array[0].has_played).is_true()
|
assert_bool(Playlist.song_object_array[0].has_played).is_true()
|
||||||
assert_int(Playlist.song_object_array.size()).is_equal(2)
|
assert_int(Playlist.song_object_array.size()).is_equal(2)
|
||||||
assert_int(_server.count("/music/rand")).is_equal(2)
|
assert_int(_server.count("/music/rand")).is_equal(2)
|
||||||
|
|
||||||
|
|
||||||
func test_title_is_hidden_until_answer_is_shown() -> void:
|
func test_title_is_hidden_until_answer_is_shown() -> void:
|
||||||
var soundtrack_label: Label = _quiz.get_node("VBoxContainer/SoundtrackLabel")
|
var soundtrack_label: Label = _quiz.get_node("VBoxContainer/SoundtrackLabel")
|
||||||
_press("NextButton")
|
_press("NextButton")
|
||||||
await _runner.simulate_frames(2)
|
await _runner.simulate_frames(2)
|
||||||
|
|
||||||
assert_str(soundtrack_label.text).is_equal("????????")
|
assert_str(soundtrack_label.text).is_equal("????????")
|
||||||
|
|
||||||
_press("ShowAnswerButton")
|
_press("ShowAnswerButton")
|
||||||
|
|
||||||
assert_str(soundtrack_label.text).is_equal("Chrono Trigger")
|
assert_str(soundtrack_label.text).is_equal("Chrono Trigger")
|
||||||
assert_int(_server.count("/music/played?song=0")).is_equal(1)
|
assert_int(_server.count("/music/played?song=0")).is_equal(1)
|
||||||
|
|
||||||
|
|
||||||
func test_reset_playlist_clears_server_and_preloads_again() -> void:
|
func test_reset_playlist_clears_server_and_preloads_again() -> void:
|
||||||
_press("NextButton")
|
_press("NextButton")
|
||||||
await _runner.simulate_frames(2)
|
await _runner.simulate_frames(2)
|
||||||
|
|
||||||
_press("ResetPlaylistButton")
|
_press("ResetPlaylistButton")
|
||||||
|
|
||||||
assert_int(_server.count("/music/reset")).is_equal(1)
|
assert_int(_server.count("/music/reset")).is_equal(1)
|
||||||
assert_int(Playlist.currently_playing_song).is_equal(-1)
|
assert_int(Playlist.currently_playing_song).is_equal(-1)
|
||||||
assert_int(Playlist.song_object_array.size()).is_equal(1)
|
assert_int(Playlist.song_object_array.size()).is_equal(1)
|
||||||
assert_bool(Playlist.song_object_array[0].has_played).is_false()
|
assert_bool(Playlist.song_object_array[0].has_played).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_reset_points_sets_all_scores_to_zero() -> void:
|
func test_reset_points_sets_all_scores_to_zero() -> void:
|
||||||
_add_player("Crono").add_point()
|
_add_player("Crono").add_point()
|
||||||
_add_player("Marle").add_point()
|
_add_player("Marle").add_point()
|
||||||
|
|
||||||
_press("ResetPointsButton")
|
_press("ResetPointsButton")
|
||||||
|
|
||||||
assert_int(Settings.player_array[0].player_score).is_equal(0)
|
assert_int(Settings.player_array[0].player_score).is_equal(0)
|
||||||
assert_int(Settings.player_array[1].player_score).is_equal(0)
|
assert_int(Settings.player_array[1].player_score).is_equal(0)
|
||||||
|
|
||||||
|
|
||||||
func test_cannot_add_more_than_max_players() -> void:
|
func test_cannot_add_more_than_max_players() -> void:
|
||||||
for i: int in Settings.MAX_NUMBER_OF_PLAYERS + 1:
|
for i: int in Settings.MAX_NUMBER_OF_PLAYERS + 1:
|
||||||
_add_player("Player %d" % i)
|
_add_player("Player %d" % i)
|
||||||
|
|
||||||
assert_int(Settings.player_array.size()).is_equal(Settings.MAX_NUMBER_OF_PLAYERS)
|
assert_int(Settings.player_array.size()).is_equal(Settings.MAX_NUMBER_OF_PLAYERS)
|
||||||
|
|
||||||
|
|
||||||
func test_cannot_add_player_without_name() -> void:
|
func test_cannot_add_player_without_name() -> void:
|
||||||
_add_player("")
|
_add_player("")
|
||||||
|
|
||||||
assert_array(Settings.player_array).is_empty()
|
assert_array(Settings.player_array).is_empty()
|
||||||
|
|
||||||
|
|
||||||
func test_failed_song_download_is_retried_until_the_server_answers() -> void:
|
func test_failed_song_download_is_retried_until_the_server_answers() -> void:
|
||||||
_quiz.song_fetch_retry_seconds = 0.05
|
_quiz.song_fetch_retry_seconds = 0.05
|
||||||
var songs_before: int = Playlist.song_object_array.size()
|
var songs_before: int = Playlist.song_object_array.size()
|
||||||
var mp3: PackedByteArray = FileAccess.get_file_as_bytes("res://tests/data/short.mp3")
|
var mp3: PackedByteArray = FileAccess.get_file_as_bytes("res://tests/data/short.mp3")
|
||||||
_server.respond_bytes("/music/rand", PackedByteArray(), 503)
|
_server.respond_bytes("/music/rand", PackedByteArray(), 503)
|
||||||
var rand_requests_before: int = _server.count("/music/rand")
|
var rand_requests_before: int = _server.count("/music/rand")
|
||||||
|
|
||||||
_quiz.fetch_song()
|
_quiz.fetch_song()
|
||||||
await await_millis(200)
|
await await_millis(200)
|
||||||
|
|
||||||
assert_int(_server.count("/music/rand") - rand_requests_before).is_greater(1)
|
assert_int(_server.count("/music/rand") - rand_requests_before).is_greater(1)
|
||||||
assert_int(Playlist.song_object_array.size()).is_equal(songs_before)
|
assert_int(Playlist.song_object_array.size()).is_equal(songs_before)
|
||||||
assert_bool(Playlist.is_song_downloading).is_true()
|
assert_bool(Playlist.is_song_downloading).is_true()
|
||||||
|
|
||||||
_server.respond_bytes("/music/rand", mp3)
|
_server.respond_bytes("/music/rand", mp3)
|
||||||
await await_millis(200)
|
await await_millis(200)
|
||||||
|
|
||||||
assert_int(Playlist.song_object_array.size()).is_equal(songs_before + 1)
|
assert_int(Playlist.song_object_array.size()).is_equal(songs_before + 1)
|
||||||
assert_bool(Playlist.is_song_downloading).is_false()
|
assert_bool(Playlist.is_song_downloading).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_failed_song_info_retries_only_that_step() -> void:
|
func test_failed_song_info_retries_only_that_step() -> void:
|
||||||
_quiz.song_fetch_retry_seconds = 0.05
|
_quiz.song_fetch_retry_seconds = 0.05
|
||||||
var songs_before: int = Playlist.song_object_array.size()
|
var songs_before: int = Playlist.song_object_array.size()
|
||||||
_server.respond_bytes("/music/info", PackedByteArray(), 503)
|
_server.respond_bytes("/music/info", PackedByteArray(), 503)
|
||||||
var rand_before: int = _server.count("/music/rand")
|
var rand_before: int = _server.count("/music/rand")
|
||||||
var queue_before: int = _server.count("/music/addQue")
|
var queue_before: int = _server.count("/music/addQue")
|
||||||
|
|
||||||
_quiz.fetch_song()
|
_quiz.fetch_song()
|
||||||
await await_millis(200)
|
await await_millis(200)
|
||||||
_next_song_is(SONG_INFO[1])
|
_next_song_is(SONG_INFO[1])
|
||||||
await await_millis(200)
|
await await_millis(200)
|
||||||
|
|
||||||
# The song was downloaded and queued once; only the info request was repeated
|
# The song was downloaded and queued once; only the info request was repeated
|
||||||
assert_int(_server.count("/music/rand") - rand_before).is_equal(1)
|
assert_int(_server.count("/music/rand") - rand_before).is_equal(1)
|
||||||
assert_int(_server.count("/music/addQue") - queue_before).is_equal(1)
|
assert_int(_server.count("/music/addQue") - queue_before).is_equal(1)
|
||||||
assert_int(Playlist.song_object_array.size()).is_equal(songs_before + 1)
|
assert_int(Playlist.song_object_array.size()).is_equal(songs_before + 1)
|
||||||
assert_str(Playlist.song_object_array.back().song_title).is_equal("Dancing Mad")
|
assert_str(Playlist.song_object_array.back().song_title).is_equal("Dancing Mad")
|
||||||
assert_bool(Playlist.is_song_downloading).is_false()
|
assert_bool(Playlist.is_song_downloading).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_preloads_as_many_songs_as_the_cache_setting() -> void:
|
func test_preloads_as_many_songs_as_the_cache_setting() -> void:
|
||||||
Playlist.number_of_tracks_to_preload = 3
|
Playlist.number_of_tracks_to_preload = 3
|
||||||
|
|
||||||
_quiz.fetch_song()
|
_quiz.fetch_song()
|
||||||
|
|
||||||
assert_int(Playlist.get_preloaded_songs()).is_equal(3)
|
assert_int(Playlist.get_preloaded_songs()).is_equal(3)
|
||||||
assert_bool(Playlist.is_song_downloading).is_false()
|
assert_bool(Playlist.is_song_downloading).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_playing_a_song_tops_the_cache_up_again() -> void:
|
func test_playing_a_song_tops_the_cache_up_again() -> void:
|
||||||
Playlist.number_of_tracks_to_preload = 3
|
Playlist.number_of_tracks_to_preload = 3
|
||||||
_quiz.fetch_song()
|
_quiz.fetch_song()
|
||||||
|
|
||||||
await _play_first_song()
|
await _play_first_song()
|
||||||
|
|
||||||
assert_int(Playlist.get_preloaded_songs()).is_equal(3)
|
assert_int(Playlist.get_preloaded_songs()).is_equal(3)
|
||||||
assert_int(Playlist.song_object_array.size()).is_equal(4)
|
assert_int(Playlist.song_object_array.size()).is_equal(4)
|
||||||
|
|
||||||
|
|
||||||
func test_cache_keeps_filling_after_a_failed_download() -> void:
|
func test_cache_keeps_filling_after_a_failed_download() -> void:
|
||||||
_quiz.song_fetch_retry_seconds = 0.05
|
_quiz.song_fetch_retry_seconds = 0.05
|
||||||
Playlist.number_of_tracks_to_preload = 3
|
Playlist.number_of_tracks_to_preload = 3
|
||||||
var mp3: PackedByteArray = FileAccess.get_file_as_bytes("res://tests/data/short.mp3")
|
var mp3: PackedByteArray = FileAccess.get_file_as_bytes("res://tests/data/short.mp3")
|
||||||
# One more download works, then the server stops answering
|
# One more download works, then the server stops answering
|
||||||
_server.fail_after("/music/rand", 1)
|
_server.fail_after("/music/rand", 1)
|
||||||
|
|
||||||
_quiz.fetch_song()
|
_quiz.fetch_song()
|
||||||
await await_millis(150)
|
await await_millis(150)
|
||||||
|
|
||||||
assert_int(Playlist.get_preloaded_songs()).is_equal(2)
|
assert_int(Playlist.get_preloaded_songs()).is_equal(2)
|
||||||
assert_bool(Playlist.is_song_downloading).is_true()
|
assert_bool(Playlist.is_song_downloading).is_true()
|
||||||
|
|
||||||
_server.respond_bytes("/music/rand", mp3)
|
_server.respond_bytes("/music/rand", mp3)
|
||||||
await await_millis(150)
|
await await_millis(150)
|
||||||
|
|
||||||
assert_int(Playlist.get_preloaded_songs()).is_equal(3)
|
assert_int(Playlist.get_preloaded_songs()).is_equal(3)
|
||||||
assert_bool(Playlist.is_song_downloading).is_false()
|
assert_bool(Playlist.is_song_downloading).is_false()
|
||||||
|
|
||||||
|
|
||||||
func _open_settings() -> void:
|
func _open_settings() -> void:
|
||||||
_press("SettingsButton")
|
_press("SettingsButton")
|
||||||
|
|
||||||
|
|
||||||
func _close_settings() -> void:
|
func _close_settings() -> void:
|
||||||
(_quiz.get_node("SettingsWindow") as Control).visible = false
|
(_quiz.get_node("SettingsWindow") as Control).visible = false
|
||||||
|
|
||||||
|
|
||||||
func _press_settings_button(unique_name: String) -> void:
|
func _press_settings_button(unique_name: String) -> void:
|
||||||
(_quiz.get_node("SettingsWindow").get_node("%" + unique_name) as Button).pressed.emit()
|
(_quiz.get_node("SettingsWindow").get_node("%" + unique_name) as Button).pressed.emit()
|
||||||
|
|
||||||
|
|
||||||
func test_raising_cache_size_does_not_download_while_settings_are_open() -> void:
|
func test_raising_cache_size_does_not_download_while_settings_are_open() -> void:
|
||||||
var downloads_before: int = _server.count("/music/rand")
|
var downloads_before: int = _server.count("/music/rand")
|
||||||
_open_settings()
|
_open_settings()
|
||||||
|
|
||||||
_press_settings_button("IncreaseCacheButton")
|
_press_settings_button("IncreaseCacheButton")
|
||||||
_press_settings_button("IncreaseCacheButton")
|
_press_settings_button("IncreaseCacheButton")
|
||||||
|
|
||||||
assert_int(Playlist.number_of_tracks_to_preload).is_equal(3)
|
assert_int(Playlist.number_of_tracks_to_preload).is_equal(3)
|
||||||
assert_int(_server.count("/music/rand")).is_equal(downloads_before)
|
assert_int(_server.count("/music/rand")).is_equal(downloads_before)
|
||||||
|
|
||||||
|
|
||||||
func test_closing_settings_fills_cache_to_new_size() -> void:
|
func test_closing_settings_fills_cache_to_new_size() -> void:
|
||||||
_open_settings()
|
_open_settings()
|
||||||
_press_settings_button("IncreaseCacheButton")
|
_press_settings_button("IncreaseCacheButton")
|
||||||
_press_settings_button("IncreaseCacheButton")
|
_press_settings_button("IncreaseCacheButton")
|
||||||
|
|
||||||
_close_settings()
|
_close_settings()
|
||||||
|
|
||||||
assert_int(Playlist.get_preloaded_songs()).is_equal(3)
|
assert_int(Playlist.get_preloaded_songs()).is_equal(3)
|
||||||
|
|
||||||
|
|
||||||
func test_changing_cache_size_back_and_forth_downloads_only_what_is_needed() -> void:
|
func test_changing_cache_size_back_and_forth_downloads_only_what_is_needed() -> void:
|
||||||
var downloads_before: int = _server.count("/music/rand")
|
var downloads_before: int = _server.count("/music/rand")
|
||||||
_open_settings()
|
_open_settings()
|
||||||
for i: int in 5:
|
for i: int in 5:
|
||||||
_press_settings_button("IncreaseCacheButton")
|
_press_settings_button("IncreaseCacheButton")
|
||||||
_press_settings_button("LowerCacheButton")
|
_press_settings_button("LowerCacheButton")
|
||||||
_press_settings_button("IncreaseCacheButton")
|
_press_settings_button("IncreaseCacheButton")
|
||||||
|
|
||||||
_close_settings()
|
_close_settings()
|
||||||
|
|
||||||
assert_int(_server.count("/music/rand") - downloads_before).is_equal(1)
|
assert_int(_server.count("/music/rand") - downloads_before).is_equal(1)
|
||||||
assert_int(Playlist.get_preloaded_songs()).is_equal(2)
|
assert_int(Playlist.get_preloaded_songs()).is_equal(2)
|
||||||
|
|
||||||
|
|
||||||
func test_closing_settings_with_full_cache_downloads_nothing() -> void:
|
func test_closing_settings_with_full_cache_downloads_nothing() -> void:
|
||||||
var downloads_before: int = _server.count("/music/rand")
|
var downloads_before: int = _server.count("/music/rand")
|
||||||
_open_settings()
|
_open_settings()
|
||||||
|
|
||||||
_close_settings()
|
_close_settings()
|
||||||
|
|
||||||
assert_int(_server.count("/music/rand")).is_equal(downloads_before)
|
assert_int(_server.count("/music/rand")).is_equal(downloads_before)
|
||||||
|
|
||||||
|
|
||||||
func test_show_answer_before_first_song_does_not_reveal_next_song() -> void:
|
func test_show_answer_before_first_song_does_not_reveal_next_song() -> void:
|
||||||
_press("ShowAnswerButton")
|
_press("ShowAnswerButton")
|
||||||
|
|
||||||
assert_bool(Playlist.song_object_array[0].is_answered).is_false()
|
assert_bool(Playlist.song_object_array[0].is_answered).is_false()
|
||||||
assert_int(_server.count("/music/played?song=-1")).is_equal(0)
|
assert_int(_server.count("/music/played?song=-1")).is_equal(0)
|
||||||
|
|
||||||
await _play_first_song()
|
await _play_first_song()
|
||||||
|
|
||||||
assert_str((_quiz.get_node("VBoxContainer/SoundtrackLabel") as Label).text) \
|
assert_str((_quiz.get_node("VBoxContainer/SoundtrackLabel") as Label).text) \
|
||||||
.is_equal("????????")
|
.is_equal("????????")
|
||||||
|
|
||||||
|
|
||||||
func test_log_adds_one_row_per_point_with_padded_time() -> void:
|
func test_log_adds_one_row_per_point_with_padded_time() -> void:
|
||||||
var log_box: VBoxContainer = _quiz.get_node("%Log").get_node("%LogVBoxContainer")
|
var log_box: VBoxContainer = _quiz.get_node("%Log").get_node("%LogVBoxContainer")
|
||||||
var crono: PlayerObject = _add_player("Crono")
|
var crono: PlayerObject = _add_player("Crono")
|
||||||
await _play_first_song()
|
await _play_first_song()
|
||||||
|
|
||||||
crono.add_point()
|
crono.add_point()
|
||||||
crono.minus_point()
|
crono.minus_point()
|
||||||
|
|
||||||
assert_int(log_box.get_child_count()).is_equal(2)
|
assert_int(log_box.get_child_count()).is_equal(2)
|
||||||
var time_pattern: RegEx = RegEx.create_from_string("^\\d\\d:\\d\\d:\\d\\d Crono got a point$")
|
var time_pattern: RegEx = RegEx.create_from_string("^\\d\\d:\\d\\d:\\d\\d Crono got a point$")
|
||||||
assert_object(time_pattern.search((log_box.get_child(0) as Label).text)).is_not_null()
|
assert_object(time_pattern.search((log_box.get_child(0) as Label).text)).is_not_null()
|
||||||
assert_str((log_box.get_child(1) as Label).text).ends_with("Crono lost a point")
|
assert_str((log_box.get_child(1) as Label).text).ends_with("Crono lost a point")
|
||||||
@@ -3,39 +3,39 @@ extends MainWindowTestSuite
|
|||||||
|
|
||||||
|
|
||||||
func _before_window_starts() -> void:
|
func _before_window_starts() -> void:
|
||||||
_server.respond_json("/music/list", [
|
_server.respond_json("/music/list", [
|
||||||
{"SongNo": 0, "Soundtrack": "Chrono Trigger", "Song": "Corridors of Time"},
|
{"SongNo": 0, "Soundtrack": "Chrono Trigger", "Song": "Corridors of Time"},
|
||||||
])
|
])
|
||||||
_next_song_is({"SongNo": 1, "Soundtrack": "Final Fantasy VI", "Song": "Dancing Mad"})
|
_next_song_is({"SongNo": 1, "Soundtrack": "Final Fantasy VI", "Song": "Dancing Mad"})
|
||||||
_server.hold("/music/list")
|
_server.hold("/music/list")
|
||||||
|
|
||||||
|
|
||||||
func test_preloaded_song_survives_a_slow_song_list() -> void:
|
func test_preloaded_song_survives_a_slow_song_list() -> void:
|
||||||
_server.release("/music/list")
|
_server.release("/music/list")
|
||||||
|
|
||||||
# The song already on the server, then the preloaded one
|
# The song already on the server, then the preloaded one
|
||||||
assert_int(Playlist.song_object_array.size()).is_equal(2)
|
assert_int(Playlist.song_object_array.size()).is_equal(2)
|
||||||
assert_str(Playlist.song_object_array[1].song_title).is_equal("Dancing Mad")
|
assert_str(Playlist.song_object_array[1].song_title).is_equal("Dancing Mad")
|
||||||
assert_int(Playlist.get_preloaded_songs()).is_equal(1)
|
assert_int(Playlist.get_preloaded_songs()).is_equal(1)
|
||||||
|
|
||||||
|
|
||||||
func test_next_plays_the_preloaded_song_after_a_slow_song_list() -> void:
|
func test_next_plays_the_preloaded_song_after_a_slow_song_list() -> void:
|
||||||
_server.release("/music/list")
|
_server.release("/music/list")
|
||||||
|
|
||||||
await _play_first_song()
|
await _play_first_song()
|
||||||
|
|
||||||
assert_int(Playlist.currently_playing_song).is_equal(1)
|
assert_int(Playlist.currently_playing_song).is_equal(1)
|
||||||
|
|
||||||
|
|
||||||
func test_failed_song_list_is_retried_before_preloading() -> void:
|
func test_failed_song_list_is_retried_before_preloading() -> void:
|
||||||
_quiz.song_fetch_retry_seconds = 0.05
|
_quiz.song_fetch_retry_seconds = 0.05
|
||||||
_server.respond_json("/music/list", [], 503)
|
_server.respond_json("/music/list", [], 503)
|
||||||
_server.release("/music/list")
|
_server.release("/music/list")
|
||||||
|
|
||||||
assert_int(_server.count("/music/rand")).is_equal(0)
|
assert_int(_server.count("/music/rand")).is_equal(0)
|
||||||
|
|
||||||
_server.respond_json("/music/list", [])
|
_server.respond_json("/music/list", [])
|
||||||
await await_millis(200)
|
await await_millis(200)
|
||||||
|
|
||||||
assert_int(_server.count("/music/rand")).is_equal(1)
|
assert_int(_server.count("/music/rand")).is_equal(1)
|
||||||
assert_int(Playlist.get_preloaded_songs()).is_equal(1)
|
assert_int(Playlist.get_preloaded_songs()).is_equal(1)
|
||||||
@@ -8,72 +8,72 @@ var _panel: MusicListPanel
|
|||||||
|
|
||||||
|
|
||||||
func before_test() -> void:
|
func before_test() -> void:
|
||||||
_snapshot = AutoloadSnapshot.take([Settings, Playlist])
|
_snapshot = AutoloadSnapshot.take([Settings, Playlist])
|
||||||
Playlist.reset_playlist()
|
Playlist.reset_playlist()
|
||||||
for i: int in 3:
|
for i: int in 3:
|
||||||
var song: SongObject = SongObject.new()
|
var song: SongObject = SongObject.new()
|
||||||
song.song_number = i
|
song.song_number = i
|
||||||
song.soundtrack_title = "Soundtrack %d" % i
|
song.soundtrack_title = "Soundtrack %d" % i
|
||||||
song.song_title = "Song %d" % i
|
song.song_title = "Song %d" % i
|
||||||
song.has_played = true
|
song.has_played = true
|
||||||
Playlist.add_to_playlist(song)
|
Playlist.add_to_playlist(song)
|
||||||
_runner = scene_runner("res://MusicListPanel.tscn")
|
_runner = scene_runner("res://MusicListPanel.tscn")
|
||||||
_panel = _runner.scene()
|
_panel = _runner.scene()
|
||||||
|
|
||||||
|
|
||||||
func after_test() -> void:
|
func after_test() -> void:
|
||||||
await await_idle_frame()
|
await await_idle_frame()
|
||||||
_snapshot.restore()
|
_snapshot.restore()
|
||||||
|
|
||||||
|
|
||||||
func _rows() -> Array[Node]:
|
func _rows() -> Array[Node]:
|
||||||
return _panel.get_node("ScrollContainer/MusicList").get_children()
|
return _panel.get_node("ScrollContainer/MusicList").get_children()
|
||||||
|
|
||||||
|
|
||||||
func test_starts_empty() -> void:
|
func test_starts_empty() -> void:
|
||||||
assert_array(_rows()).is_empty()
|
assert_array(_rows()).is_empty()
|
||||||
|
|
||||||
|
|
||||||
func test_refresh_shows_one_row_per_song_in_order() -> void:
|
func test_refresh_shows_one_row_per_song_in_order() -> void:
|
||||||
_panel.refresh()
|
_panel.refresh()
|
||||||
|
|
||||||
assert_array(_rows().map(func(row: SongListObject) -> int: return row.song_object.song_number)) \
|
assert_array(_rows().map(func(row: SongListObject) -> int: return row.song_object.song_number)) \
|
||||||
.contains_exactly([0, 1, 2])
|
.contains_exactly([0, 1, 2])
|
||||||
|
|
||||||
|
|
||||||
func test_refresh_again_replaces_the_rows() -> void:
|
func test_refresh_again_replaces_the_rows() -> void:
|
||||||
_panel.refresh()
|
_panel.refresh()
|
||||||
Playlist.song_object_array.pop_back()
|
Playlist.song_object_array.pop_back()
|
||||||
|
|
||||||
_panel.refresh()
|
_panel.refresh()
|
||||||
|
|
||||||
assert_int(_rows().size()).is_equal(2)
|
assert_int(_rows().size()).is_equal(2)
|
||||||
|
|
||||||
|
|
||||||
func test_clicking_a_row_tells_which_song() -> void:
|
func test_clicking_a_row_tells_which_song() -> void:
|
||||||
_panel.refresh()
|
_panel.refresh()
|
||||||
await _runner.simulate_frames(2)
|
await _runner.simulate_frames(2)
|
||||||
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_panel))
|
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_panel))
|
||||||
var row: Control = _rows()[1]
|
var row: Control = _rows()[1]
|
||||||
# The left end of the row is the song text, not one of the player icons
|
# The left end of the row is the song text, not one of the player icons
|
||||||
var target: Vector2 = row.get_global_rect().position + Vector2(20, row.size.y / 2)
|
var target: Vector2 = row.get_global_rect().position + Vector2(20, row.size.y / 2)
|
||||||
|
|
||||||
_runner.set_mouse_position(_panel.get_viewport().get_final_transform() * target)
|
_runner.set_mouse_position(_panel.get_viewport().get_final_transform() * target)
|
||||||
await _runner.simulate_mouse_button_pressed(MOUSE_BUTTON_LEFT)
|
await _runner.simulate_mouse_button_pressed(MOUSE_BUTTON_LEFT)
|
||||||
await _runner.await_input_processed()
|
await _runner.await_input_processed()
|
||||||
|
|
||||||
await signals.is_emitted("song_clicked", [1])
|
await signals.is_emitted("song_clicked", [1])
|
||||||
|
|
||||||
|
|
||||||
func test_right_click_does_nothing() -> void:
|
func test_right_click_does_nothing() -> void:
|
||||||
_panel.refresh()
|
_panel.refresh()
|
||||||
await _runner.simulate_frames(2)
|
await _runner.simulate_frames(2)
|
||||||
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_panel))
|
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_panel))
|
||||||
var row: Control = _rows()[0]
|
var row: Control = _rows()[0]
|
||||||
|
|
||||||
_runner.set_mouse_position(_panel.get_viewport().get_final_transform()
|
_runner.set_mouse_position(_panel.get_viewport().get_final_transform()
|
||||||
* (row.get_global_rect().position + Vector2(20, row.size.y / 2)))
|
* (row.get_global_rect().position + Vector2(20, row.size.y / 2)))
|
||||||
await _runner.simulate_mouse_button_pressed(MOUSE_BUTTON_RIGHT)
|
await _runner.simulate_mouse_button_pressed(MOUSE_BUTTON_RIGHT)
|
||||||
await _runner.await_input_processed()
|
await _runner.await_input_processed()
|
||||||
|
|
||||||
await signals.wait_until(200).is_not_emitted("song_clicked")
|
await signals.wait_until(200).is_not_emitted("song_clicked")
|
||||||
@@ -10,143 +10,143 @@ var _lucca: PlayerObject
|
|||||||
|
|
||||||
|
|
||||||
func before_test() -> void:
|
func before_test() -> void:
|
||||||
super()
|
super()
|
||||||
_crono = _add_player("Crono")
|
_crono = _add_player("Crono")
|
||||||
_marle = _add_player("Marle")
|
_marle = _add_player("Marle")
|
||||||
_lucca = _add_player("Lucca")
|
_lucca = _add_player("Lucca")
|
||||||
await _play_first_song()
|
await _play_first_song()
|
||||||
|
|
||||||
|
|
||||||
func _song_points() -> Array[String]:
|
func _song_points() -> Array[String]:
|
||||||
return Playlist.song_object_array[Playlist.currently_playing_song].players_given_point
|
return Playlist.song_object_array[Playlist.currently_playing_song].players_given_point
|
||||||
|
|
||||||
|
|
||||||
func test_alt_number_gives_point_to_player_in_that_row() -> void:
|
func test_alt_number_gives_point_to_player_in_that_row() -> void:
|
||||||
await _give_point_with_keybind(2)
|
await _give_point_with_keybind(2)
|
||||||
|
|
||||||
assert_array(_scores()).contains_exactly([0, 1, 0])
|
assert_array(_scores()).contains_exactly([0, 1, 0])
|
||||||
assert_array(_song_points()).contains_exactly([_marle.id])
|
assert_array(_song_points()).contains_exactly([_marle.id])
|
||||||
|
|
||||||
|
|
||||||
func test_ctrl_alt_number_takes_point_from_player_in_that_row() -> void:
|
func test_ctrl_alt_number_takes_point_from_player_in_that_row() -> void:
|
||||||
await _give_point_with_keybind(3)
|
await _give_point_with_keybind(3)
|
||||||
await _give_point_with_keybind(3)
|
await _give_point_with_keybind(3)
|
||||||
|
|
||||||
await _take_point_with_keybind(3)
|
await _take_point_with_keybind(3)
|
||||||
|
|
||||||
assert_array(_scores()).contains_exactly([0, 0, 1])
|
assert_array(_scores()).contains_exactly([0, 0, 1])
|
||||||
|
|
||||||
|
|
||||||
func test_taking_last_point_removes_player_from_song() -> void:
|
func test_taking_last_point_removes_player_from_song() -> void:
|
||||||
await _give_point_with_keybind(1)
|
await _give_point_with_keybind(1)
|
||||||
|
|
||||||
await _take_point_with_keybind(1)
|
await _take_point_with_keybind(1)
|
||||||
|
|
||||||
assert_int(_crono.player_score).is_equal(0)
|
assert_int(_crono.player_score).is_equal(0)
|
||||||
assert_array(_song_points()).is_empty()
|
assert_array(_song_points()).is_empty()
|
||||||
|
|
||||||
|
|
||||||
func test_each_keybind_only_affects_its_own_player() -> void:
|
func test_each_keybind_only_affects_its_own_player() -> void:
|
||||||
await _give_point_with_keybind(1)
|
await _give_point_with_keybind(1)
|
||||||
await _give_point_with_keybind(3)
|
await _give_point_with_keybind(3)
|
||||||
await _give_point_with_keybind(3)
|
await _give_point_with_keybind(3)
|
||||||
|
|
||||||
assert_int(_crono.player_score).is_equal(1)
|
assert_int(_crono.player_score).is_equal(1)
|
||||||
assert_int(_marle.player_score).is_equal(0)
|
assert_int(_marle.player_score).is_equal(0)
|
||||||
assert_int(_lucca.player_score).is_equal(2)
|
assert_int(_lucca.player_score).is_equal(2)
|
||||||
assert_array(_song_points()).contains_exactly([_crono.id, _lucca.id])
|
assert_array(_song_points()).contains_exactly([_crono.id, _lucca.id])
|
||||||
|
|
||||||
|
|
||||||
func test_number_without_player_does_nothing() -> void:
|
func test_number_without_player_does_nothing() -> void:
|
||||||
await _give_point_with_keybind(4)
|
await _give_point_with_keybind(4)
|
||||||
|
|
||||||
assert_array(_scores()).contains_exactly([0, 0, 0])
|
assert_array(_scores()).contains_exactly([0, 0, 0])
|
||||||
assert_array(_song_points()).is_empty()
|
assert_array(_song_points()).is_empty()
|
||||||
|
|
||||||
|
|
||||||
func test_keybinds_move_up_when_first_player_is_removed() -> void:
|
func test_keybinds_move_up_when_first_player_is_removed() -> void:
|
||||||
await _remove_player(_crono)
|
await _remove_player(_crono)
|
||||||
|
|
||||||
await _give_point_with_keybind(1)
|
await _give_point_with_keybind(1)
|
||||||
await _give_point_with_keybind(2)
|
await _give_point_with_keybind(2)
|
||||||
await _give_point_with_keybind(2)
|
await _give_point_with_keybind(2)
|
||||||
|
|
||||||
assert_int(_marle.player_score).is_equal(1)
|
assert_int(_marle.player_score).is_equal(1)
|
||||||
assert_int(_lucca.player_score).is_equal(2)
|
assert_int(_lucca.player_score).is_equal(2)
|
||||||
assert_array(_song_points()).contains_exactly([_marle.id, _lucca.id])
|
assert_array(_song_points()).contains_exactly([_marle.id, _lucca.id])
|
||||||
|
|
||||||
|
|
||||||
func test_keybind_after_last_row_does_nothing_after_removal() -> void:
|
func test_keybind_after_last_row_does_nothing_after_removal() -> void:
|
||||||
await _remove_player(_marle)
|
await _remove_player(_marle)
|
||||||
|
|
||||||
await _give_point_with_keybind(3)
|
await _give_point_with_keybind(3)
|
||||||
|
|
||||||
assert_int(_crono.player_score).is_equal(0)
|
assert_int(_crono.player_score).is_equal(0)
|
||||||
assert_int(_lucca.player_score).is_equal(0)
|
assert_int(_lucca.player_score).is_equal(0)
|
||||||
|
|
||||||
|
|
||||||
func test_removing_player_removes_only_their_points() -> void:
|
func test_removing_player_removes_only_their_points() -> void:
|
||||||
await _give_point_with_keybind(1)
|
await _give_point_with_keybind(1)
|
||||||
await _give_point_with_keybind(2)
|
await _give_point_with_keybind(2)
|
||||||
await _give_point_with_keybind(3)
|
await _give_point_with_keybind(3)
|
||||||
|
|
||||||
await _remove_player(_marle)
|
await _remove_player(_marle)
|
||||||
|
|
||||||
assert_array(_song_points()).contains_exactly([_crono.id, _lucca.id])
|
assert_array(_song_points()).contains_exactly([_crono.id, _lucca.id])
|
||||||
assert_int(_crono.player_score).is_equal(1)
|
assert_int(_crono.player_score).is_equal(1)
|
||||||
assert_int(_lucca.player_score).is_equal(1)
|
assert_int(_lucca.player_score).is_equal(1)
|
||||||
|
|
||||||
|
|
||||||
func test_new_player_gets_next_free_keybind_after_removal() -> void:
|
func test_new_player_gets_next_free_keybind_after_removal() -> void:
|
||||||
await _remove_player(_marle)
|
await _remove_player(_marle)
|
||||||
var robo: PlayerObject = _add_player("Robo")
|
var robo: PlayerObject = _add_player("Robo")
|
||||||
|
|
||||||
await _give_point_with_keybind(2)
|
await _give_point_with_keybind(2)
|
||||||
await _give_point_with_keybind(3)
|
await _give_point_with_keybind(3)
|
||||||
|
|
||||||
assert_int(_lucca.player_score).is_equal(1)
|
assert_int(_lucca.player_score).is_equal(1)
|
||||||
assert_int(robo.player_score).is_equal(1)
|
assert_int(robo.player_score).is_equal(1)
|
||||||
assert_int(_crono.player_score).is_equal(0)
|
assert_int(_crono.player_score).is_equal(0)
|
||||||
assert_array(_song_points()).contains_exactly([_lucca.id, robo.id])
|
assert_array(_song_points()).contains_exactly([_lucca.id, robo.id])
|
||||||
|
|
||||||
|
|
||||||
func test_new_player_does_not_inherit_removed_players_points() -> void:
|
func test_new_player_does_not_inherit_removed_players_points() -> void:
|
||||||
await _give_point_with_keybind(3)
|
await _give_point_with_keybind(3)
|
||||||
await _remove_player(_lucca)
|
await _remove_player(_lucca)
|
||||||
|
|
||||||
var robo: PlayerObject = _add_player("Robo")
|
var robo: PlayerObject = _add_player("Robo")
|
||||||
|
|
||||||
assert_int(robo.player_score).is_equal(0)
|
assert_int(robo.player_score).is_equal(0)
|
||||||
assert_array(_song_points()).is_empty()
|
assert_array(_song_points()).is_empty()
|
||||||
|
|
||||||
|
|
||||||
func test_points_follow_players_through_several_changes() -> void:
|
func test_points_follow_players_through_several_changes() -> void:
|
||||||
await _give_point_with_keybind(1)
|
await _give_point_with_keybind(1)
|
||||||
await _remove_player(_crono)
|
await _remove_player(_crono)
|
||||||
var robo: PlayerObject = _add_player("Robo")
|
var robo: PlayerObject = _add_player("Robo")
|
||||||
await _give_point_with_keybind(1)
|
await _give_point_with_keybind(1)
|
||||||
await _remove_player(_marle)
|
await _remove_player(_marle)
|
||||||
var ayla: PlayerObject = _add_player("Ayla")
|
var ayla: PlayerObject = _add_player("Ayla")
|
||||||
await _give_point_with_keybind(3)
|
await _give_point_with_keybind(3)
|
||||||
await _give_point_with_keybind(2)
|
await _give_point_with_keybind(2)
|
||||||
await _take_point_with_keybind(2)
|
await _take_point_with_keybind(2)
|
||||||
|
|
||||||
# Rows are now: Lucca, Robo, Ayla
|
# Rows are now: Lucca, Robo, Ayla
|
||||||
assert_array(Settings.player_array).contains_exactly([_lucca, robo, ayla])
|
assert_array(Settings.player_array).contains_exactly([_lucca, robo, ayla])
|
||||||
assert_int(_lucca.player_score).is_equal(0)
|
assert_int(_lucca.player_score).is_equal(0)
|
||||||
assert_int(robo.player_score).is_equal(0)
|
assert_int(robo.player_score).is_equal(0)
|
||||||
assert_int(ayla.player_score).is_equal(1)
|
assert_int(ayla.player_score).is_equal(1)
|
||||||
assert_array(_song_points()).contains_exactly([ayla.id])
|
assert_array(_song_points()).contains_exactly([ayla.id])
|
||||||
|
|
||||||
|
|
||||||
func test_player_list_shows_rows_in_player_order() -> void:
|
func test_player_list_shows_rows_in_player_order() -> void:
|
||||||
await _remove_player(_crono)
|
await _remove_player(_crono)
|
||||||
var robo: PlayerObject = _add_player("Robo")
|
var robo: PlayerObject = _add_player("Robo")
|
||||||
|
|
||||||
var rows: Array[Node] = _quiz.get_node(
|
var rows: Array[Node] = _quiz.get_node(
|
||||||
"PlayersPanel/VBoxContainer/ScrollContainer/PlayersListVBoxContainer").get_children()
|
"PlayersPanel/VBoxContainer/ScrollContainer/PlayersListVBoxContainer").get_children()
|
||||||
|
|
||||||
assert_array(rows.map(func(row: Player) -> PlayerObject: return row.player_object)) \
|
assert_array(rows.map(func(row: Player) -> PlayerObject: return row.player_object)) \
|
||||||
.contains_exactly([_marle, _lucca, robo])
|
.contains_exactly([_marle, _lucca, robo])
|
||||||
assert_array(rows.map(func(row: Player) -> int: return row.list_index)) \
|
assert_array(rows.map(func(row: Player) -> int: return row.list_index)) \
|
||||||
.contains_exactly([0, 1, 2])
|
.contains_exactly([0, 1, 2])
|
||||||
@@ -8,139 +8,139 @@ var _panel: PlayersPanel
|
|||||||
|
|
||||||
|
|
||||||
func before_test() -> void:
|
func before_test() -> void:
|
||||||
_snapshot = AutoloadSnapshot.take([Settings])
|
_snapshot = AutoloadSnapshot.take([Settings])
|
||||||
Settings.player_array.clear()
|
Settings.player_array.clear()
|
||||||
Settings.edit_players = false
|
Settings.edit_players = false
|
||||||
_runner = scene_runner("res://PlayersPanel.tscn")
|
_runner = scene_runner("res://PlayersPanel.tscn")
|
||||||
_panel = _runner.scene()
|
_panel = _runner.scene()
|
||||||
|
|
||||||
|
|
||||||
func after_test() -> void:
|
func after_test() -> void:
|
||||||
await await_idle_frame()
|
await await_idle_frame()
|
||||||
_snapshot.restore()
|
_snapshot.restore()
|
||||||
|
|
||||||
|
|
||||||
func _rows() -> Array[Node]:
|
func _rows() -> Array[Node]:
|
||||||
return _panel.players_list_container.get_children()
|
return _panel.players_list_container.get_children()
|
||||||
|
|
||||||
|
|
||||||
func _add(player_name: String) -> void:
|
func _add(player_name: String) -> void:
|
||||||
_panel.new_player_name_field.text = player_name
|
_panel.new_player_name_field.text = player_name
|
||||||
_panel.add_player()
|
_panel.add_player()
|
||||||
|
|
||||||
|
|
||||||
func _click(control: Control) -> void:
|
func _click(control: Control) -> void:
|
||||||
_runner.set_mouse_position(_panel.get_viewport().get_final_transform()
|
_runner.set_mouse_position(_panel.get_viewport().get_final_transform()
|
||||||
* control.get_global_rect().get_center())
|
* control.get_global_rect().get_center())
|
||||||
await _runner.simulate_mouse_button_pressed(MOUSE_BUTTON_LEFT)
|
await _runner.simulate_mouse_button_pressed(MOUSE_BUTTON_LEFT)
|
||||||
await _runner.await_input_processed()
|
await _runner.await_input_processed()
|
||||||
|
|
||||||
|
|
||||||
func test_add_button_shows_and_hides_the_add_row() -> void:
|
func test_add_button_shows_and_hides_the_add_row() -> void:
|
||||||
assert_bool(_panel.add_player_container.visible).is_false()
|
assert_bool(_panel.add_player_container.visible).is_false()
|
||||||
|
|
||||||
await _click(_panel.add_players_button)
|
await _click(_panel.add_players_button)
|
||||||
assert_bool(_panel.add_player_container.visible).is_true()
|
assert_bool(_panel.add_player_container.visible).is_true()
|
||||||
assert_bool(Settings.edit_players).is_true()
|
assert_bool(Settings.edit_players).is_true()
|
||||||
|
|
||||||
await _click(_panel.add_players_button)
|
await _click(_panel.add_players_button)
|
||||||
assert_bool(_panel.add_player_container.visible).is_false()
|
assert_bool(_panel.add_player_container.visible).is_false()
|
||||||
assert_bool(Settings.edit_players).is_false()
|
assert_bool(Settings.edit_players).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_adding_a_name_adds_a_player_and_a_row() -> void:
|
func test_adding_a_name_adds_a_player_and_a_row() -> void:
|
||||||
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_panel))
|
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_panel))
|
||||||
|
|
||||||
_add("Crono")
|
_add("Crono")
|
||||||
|
|
||||||
assert_int(Settings.player_array.size()).is_equal(1)
|
assert_int(Settings.player_array.size()).is_equal(1)
|
||||||
var crono: PlayerObject = Settings.player_array[0]
|
var crono: PlayerObject = Settings.player_array[0]
|
||||||
assert_str(crono.player_name).is_equal("Crono")
|
assert_str(crono.player_name).is_equal("Crono")
|
||||||
await signals.is_emitted("player_added", [crono])
|
await signals.is_emitted("player_added", [crono])
|
||||||
assert_str(_panel.new_player_name_field.text).is_empty()
|
assert_str(_panel.new_player_name_field.text).is_empty()
|
||||||
assert_object((_rows()[0] as Player).player_object).is_same(crono)
|
assert_object((_rows()[0] as Player).player_object).is_same(crono)
|
||||||
|
|
||||||
|
|
||||||
func test_add_button_in_the_row_adds_the_player() -> void:
|
func test_add_button_in_the_row_adds_the_player() -> void:
|
||||||
await _click(_panel.add_players_button)
|
await _click(_panel.add_players_button)
|
||||||
_panel.new_player_name_field.text = "Marle"
|
_panel.new_player_name_field.text = "Marle"
|
||||||
|
|
||||||
await _click(_panel.add_player_button)
|
await _click(_panel.add_player_button)
|
||||||
|
|
||||||
assert_int(Settings.player_array.size()).is_equal(1)
|
assert_int(Settings.player_array.size()).is_equal(1)
|
||||||
|
|
||||||
|
|
||||||
func test_enter_in_the_name_field_adds_the_player() -> void:
|
func test_enter_in_the_name_field_adds_the_player() -> void:
|
||||||
await _click(_panel.add_players_button)
|
await _click(_panel.add_players_button)
|
||||||
_panel.new_player_name_field.text = "Lucca"
|
_panel.new_player_name_field.text = "Lucca"
|
||||||
_panel.new_player_name_field.grab_focus()
|
_panel.new_player_name_field.grab_focus()
|
||||||
|
|
||||||
_runner.simulate_key_pressed(KEY_ENTER)
|
_runner.simulate_key_pressed(KEY_ENTER)
|
||||||
await _runner.await_input_processed()
|
await _runner.await_input_processed()
|
||||||
|
|
||||||
assert_array(Settings.player_array.map(
|
assert_array(Settings.player_array.map(
|
||||||
func(p: PlayerObject) -> String: return p.player_name)).contains_exactly(["Lucca"])
|
func(p: PlayerObject) -> String: return p.player_name)).contains_exactly(["Lucca"])
|
||||||
|
|
||||||
|
|
||||||
func test_empty_name_adds_nobody() -> void:
|
func test_empty_name_adds_nobody() -> void:
|
||||||
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_panel))
|
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_panel))
|
||||||
|
|
||||||
_add("")
|
_add("")
|
||||||
|
|
||||||
assert_array(Settings.player_array).is_empty()
|
assert_array(Settings.player_array).is_empty()
|
||||||
assert_array(_rows()).is_empty()
|
assert_array(_rows()).is_empty()
|
||||||
await signals.wait_until(200).is_not_emitted("player_added")
|
await signals.wait_until(200).is_not_emitted("player_added")
|
||||||
|
|
||||||
|
|
||||||
func test_cannot_add_more_than_max_players() -> void:
|
func test_cannot_add_more_than_max_players() -> void:
|
||||||
for i: int in Settings.MAX_NUMBER_OF_PLAYERS + 1:
|
for i: int in Settings.MAX_NUMBER_OF_PLAYERS + 1:
|
||||||
_add("Player %d" % i)
|
_add("Player %d" % i)
|
||||||
|
|
||||||
assert_int(Settings.player_array.size()).is_equal(Settings.MAX_NUMBER_OF_PLAYERS)
|
assert_int(Settings.player_array.size()).is_equal(Settings.MAX_NUMBER_OF_PLAYERS)
|
||||||
assert_int(_rows().size()).is_equal(Settings.MAX_NUMBER_OF_PLAYERS)
|
assert_int(_rows().size()).is_equal(Settings.MAX_NUMBER_OF_PLAYERS)
|
||||||
|
|
||||||
|
|
||||||
func test_rows_follow_player_order_and_numbering() -> void:
|
func test_rows_follow_player_order_and_numbering() -> void:
|
||||||
_add("Crono")
|
_add("Crono")
|
||||||
_add("Marle")
|
_add("Marle")
|
||||||
_add("Lucca")
|
_add("Lucca")
|
||||||
|
|
||||||
assert_array(_rows().map(func(row: Player) -> String: return row.player_object.player_name)) \
|
assert_array(_rows().map(func(row: Player) -> String: return row.player_object.player_name)) \
|
||||||
.contains_exactly(["Crono", "Marle", "Lucca"])
|
.contains_exactly(["Crono", "Marle", "Lucca"])
|
||||||
assert_array(_rows().map(func(row: Player) -> int: return row.list_index)) \
|
assert_array(_rows().map(func(row: Player) -> int: return row.list_index)) \
|
||||||
.contains_exactly([0, 1, 2])
|
.contains_exactly([0, 1, 2])
|
||||||
|
|
||||||
|
|
||||||
func test_remove_button_removes_the_player_and_row() -> void:
|
func test_remove_button_removes_the_player_and_row() -> void:
|
||||||
_add("Crono")
|
_add("Crono")
|
||||||
_add("Marle")
|
_add("Marle")
|
||||||
var crono: PlayerObject = Settings.player_array[0]
|
var crono: PlayerObject = Settings.player_array[0]
|
||||||
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_panel))
|
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_panel))
|
||||||
|
|
||||||
(_rows()[0].get_node("HBoxContainer/RemovePlayer") as BaseButton).pressed.emit()
|
(_rows()[0].get_node("HBoxContainer/RemovePlayer") as BaseButton).pressed.emit()
|
||||||
|
|
||||||
await signals.is_emitted("player_removed", [crono])
|
await signals.is_emitted("player_removed", [crono])
|
||||||
assert_array(Settings.player_array.map(
|
assert_array(Settings.player_array.map(
|
||||||
func(p: PlayerObject) -> String: return p.player_name)).contains_exactly(["Marle"])
|
func(p: PlayerObject) -> String: return p.player_name)).contains_exactly(["Marle"])
|
||||||
assert_int(_rows().size()).is_equal(1)
|
assert_int(_rows().size()).is_equal(1)
|
||||||
assert_int((_rows()[0] as Player).list_index).is_equal(0)
|
assert_int((_rows()[0] as Player).list_index).is_equal(0)
|
||||||
|
|
||||||
|
|
||||||
func test_character_button_asks_for_a_new_character() -> void:
|
func test_character_button_asks_for_a_new_character() -> void:
|
||||||
_add("Crono")
|
_add("Crono")
|
||||||
var row: Player = _rows()[0]
|
var row: Player = _rows()[0]
|
||||||
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_panel))
|
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_panel))
|
||||||
|
|
||||||
(row.get_node("HBoxContainer/Character") as BaseButton).pressed.emit()
|
(row.get_node("HBoxContainer/Character") as BaseButton).pressed.emit()
|
||||||
|
|
||||||
await signals.is_emitted("change_character_requested", [row, "Crono"])
|
await signals.is_emitted("change_character_requested", [row, "Crono"])
|
||||||
|
|
||||||
|
|
||||||
func test_reload_shows_new_scores() -> void:
|
func test_reload_shows_new_scores() -> void:
|
||||||
_add("Crono")
|
_add("Crono")
|
||||||
Settings.player_array[0].player_score = 3
|
Settings.player_array[0].player_score = 3
|
||||||
|
|
||||||
_panel.reload()
|
_panel.reload()
|
||||||
|
|
||||||
assert_str(((_rows()[0] as Player).get_node("HBoxContainer/Name") as Label).text) \
|
assert_str(((_rows()[0] as Player).get_node("HBoxContainer/Name") as Label).text) \
|
||||||
.ends_with("Crono: 3")
|
.ends_with("Crono: 3")
|
||||||
@@ -5,127 +5,127 @@ extends MainWindowTestSuite
|
|||||||
|
|
||||||
## Popups opened from the top bar, in the main window.
|
## Popups opened from the top bar, in the main window.
|
||||||
const MAIN_POPUPS: Array[String] = [
|
const MAIN_POPUPS: Array[String] = [
|
||||||
"Search", "SyncWindow", "QRWindow", "ShortcutsWindow", "AboutWindow",
|
"Search", "SyncWindow", "QRWindow", "ShortcutsWindow", "AboutWindow",
|
||||||
]
|
]
|
||||||
|
|
||||||
## Popups opened from the quiz, in the Quiz scene.
|
## Popups opened from the quiz, in the Quiz scene.
|
||||||
const QUIZ_POPUPS: Array[String] = [
|
const QUIZ_POPUPS: Array[String] = [
|
||||||
"SettingsWindow", "NewCharacterSelect", "WinnerWindow", "Log",
|
"SettingsWindow", "NewCharacterSelect", "WinnerWindow", "Log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
func _popup(node_name: String) -> PopupWindow:
|
func _popup(node_name: String) -> PopupWindow:
|
||||||
return _quiz.get_node(node_name) if node_name in QUIZ_POPUPS \
|
return _quiz.get_node(node_name) if node_name in QUIZ_POPUPS \
|
||||||
else _window.get_node(node_name)
|
else _window.get_node(node_name)
|
||||||
|
|
||||||
|
|
||||||
## The backdrop that shows behind [param popup].
|
## The backdrop that shows behind [param popup].
|
||||||
func _backdrop(popup: PopupWindow = _popup("SettingsWindow")) -> ColorRect:
|
func _backdrop(popup: PopupWindow = _popup("SettingsWindow")) -> ColorRect:
|
||||||
return popup.get_parent().get_node("PopupBackdrop")
|
return popup.get_parent().get_node("PopupBackdrop")
|
||||||
|
|
||||||
|
|
||||||
## A point on screen outside the popup's panel.
|
## A point on screen outside the popup's panel.
|
||||||
func _outside(popup: PopupWindow) -> Vector2:
|
func _outside(popup: PopupWindow) -> Vector2:
|
||||||
var rect: Rect2 = popup.panel.get_global_rect()
|
var rect: Rect2 = popup.panel.get_global_rect()
|
||||||
return Vector2(rect.end.x + 5, rect.end.y + 5) if rect.end.x < 1900 \
|
return Vector2(rect.end.x + 5, rect.end.y + 5) if rect.end.x < 1900 \
|
||||||
else Vector2(rect.position.x - 5, rect.position.y - 5)
|
else Vector2(rect.position.x - 5, rect.position.y - 5)
|
||||||
|
|
||||||
|
|
||||||
func test_backdrops_are_hidden_without_popups() -> void:
|
func test_backdrops_are_hidden_without_popups() -> void:
|
||||||
assert_bool(_backdrop(_popup("SettingsWindow")).visible).is_false()
|
assert_bool(_backdrop(_popup("SettingsWindow")).visible).is_false()
|
||||||
assert_bool(_backdrop(_popup("AboutWindow")).visible).is_false()
|
assert_bool(_backdrop(_popup("AboutWindow")).visible).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_backdrops_cover_the_whole_window() -> void:
|
func test_backdrops_cover_the_whole_window() -> void:
|
||||||
for node_name: String in ["SettingsWindow", "AboutWindow"]:
|
for node_name: String in ["SettingsWindow", "AboutWindow"]:
|
||||||
var popup: PopupWindow = _popup(node_name)
|
var popup: PopupWindow = _popup(node_name)
|
||||||
popup.open()
|
popup.open()
|
||||||
|
|
||||||
assert_object(_backdrop(popup).get_global_rect()).override_failure_message(
|
assert_object(_backdrop(popup).get_global_rect()).override_failure_message(
|
||||||
"%s: backdrop does not cover the window" % node_name) \
|
"%s: backdrop does not cover the window" % node_name) \
|
||||||
.is_equal(_window.get_viewport_rect())
|
.is_equal(_window.get_viewport_rect())
|
||||||
popup.close()
|
popup.close()
|
||||||
|
|
||||||
|
|
||||||
func test_every_popup_is_a_popup_window() -> void:
|
func test_every_popup_is_a_popup_window() -> void:
|
||||||
for node_name: String in MAIN_POPUPS + QUIZ_POPUPS:
|
for node_name: String in MAIN_POPUPS + QUIZ_POPUPS:
|
||||||
assert_object(_popup(node_name)).is_instanceof(PopupWindow)
|
assert_object(_popup(node_name)).is_instanceof(PopupWindow)
|
||||||
|
|
||||||
|
|
||||||
func test_every_popup_shows_backdrop_and_closes_on_outside_click() -> void:
|
func test_every_popup_shows_backdrop_and_closes_on_outside_click() -> void:
|
||||||
for node_name: String in MAIN_POPUPS + QUIZ_POPUPS:
|
for node_name: String in MAIN_POPUPS + QUIZ_POPUPS:
|
||||||
var popup: PopupWindow = _popup(node_name)
|
var popup: PopupWindow = _popup(node_name)
|
||||||
popup.open()
|
popup.open()
|
||||||
await _runner.simulate_frames(1)
|
await _runner.simulate_frames(1)
|
||||||
assert_bool(_backdrop(popup).visible).override_failure_message(
|
assert_bool(_backdrop(popup).visible).override_failure_message(
|
||||||
"%s: backdrop not shown" % node_name).is_true()
|
"%s: backdrop not shown" % node_name).is_true()
|
||||||
|
|
||||||
await _click_at(_outside(popup))
|
await _click_at(_outside(popup))
|
||||||
|
|
||||||
assert_bool(popup.visible).override_failure_message(
|
assert_bool(popup.visible).override_failure_message(
|
||||||
"%s: not closed by outside click" % node_name).is_false()
|
"%s: not closed by outside click" % node_name).is_false()
|
||||||
assert_bool(_backdrop(popup).visible).override_failure_message(
|
assert_bool(_backdrop(popup).visible).override_failure_message(
|
||||||
"%s: backdrop still shown" % node_name).is_false()
|
"%s: backdrop still shown" % node_name).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_click_inside_popup_keeps_it_open() -> void:
|
func test_click_inside_popup_keeps_it_open() -> void:
|
||||||
var settings: PopupWindow = _popup("SettingsWindow")
|
var settings: PopupWindow = _popup("SettingsWindow")
|
||||||
settings.open()
|
settings.open()
|
||||||
await _runner.simulate_frames(1)
|
await _runner.simulate_frames(1)
|
||||||
|
|
||||||
await _click_at(settings.panel.get_global_rect().get_center())
|
await _click_at(settings.panel.get_global_rect().get_center())
|
||||||
|
|
||||||
assert_bool(settings.visible).is_true()
|
assert_bool(settings.visible).is_true()
|
||||||
|
|
||||||
|
|
||||||
func test_closing_click_does_not_press_button_behind_popup() -> void:
|
func test_closing_click_does_not_press_button_behind_popup() -> void:
|
||||||
var settings: PopupWindow = _popup("SettingsWindow")
|
var settings: PopupWindow = _popup("SettingsWindow")
|
||||||
var reset_button: Button = _quiz.get_node("ResetPlaylistButton")
|
var reset_button: Button = _quiz.get_node("ResetPlaylistButton")
|
||||||
settings.open()
|
settings.open()
|
||||||
await _runner.simulate_frames(1)
|
await _runner.simulate_frames(1)
|
||||||
assert_bool(settings.panel.get_global_rect().intersects(reset_button.get_global_rect())) \
|
assert_bool(settings.panel.get_global_rect().intersects(reset_button.get_global_rect())) \
|
||||||
.is_false()
|
.is_false()
|
||||||
|
|
||||||
await _click_at(reset_button.get_global_rect().get_center())
|
await _click_at(reset_button.get_global_rect().get_center())
|
||||||
|
|
||||||
assert_bool(settings.visible).is_false()
|
assert_bool(settings.visible).is_false()
|
||||||
assert_int(_server.count("/music/reset")).is_equal(0)
|
assert_int(_server.count("/music/reset")).is_equal(0)
|
||||||
|
|
||||||
|
|
||||||
func test_button_works_again_after_popup_closed() -> void:
|
func test_button_works_again_after_popup_closed() -> void:
|
||||||
var reset_button: Button = _quiz.get_node("ResetPlaylistButton")
|
var reset_button: Button = _quiz.get_node("ResetPlaylistButton")
|
||||||
|
|
||||||
await _click_at(reset_button.get_global_rect().get_center())
|
await _click_at(reset_button.get_global_rect().get_center())
|
||||||
|
|
||||||
assert_int(_server.count("/music/reset")).is_equal(1)
|
assert_int(_server.count("/music/reset")).is_equal(1)
|
||||||
|
|
||||||
|
|
||||||
func test_closing_search_clears_the_search() -> void:
|
func test_closing_search_clears_the_search() -> void:
|
||||||
var search: PopupWindow = _popup("Search")
|
var search: PopupWindow = _popup("Search")
|
||||||
search.open()
|
search.open()
|
||||||
var search_bar: TextEdit = search.get_node("Searchbar")
|
var search_bar: TextEdit = search.get_node("Searchbar")
|
||||||
search_bar.text = "mario"
|
search_bar.text = "mario"
|
||||||
|
|
||||||
search.close()
|
search.close()
|
||||||
|
|
||||||
assert_str(search_bar.text).is_empty()
|
assert_str(search_bar.text).is_empty()
|
||||||
|
|
||||||
|
|
||||||
func test_closing_character_select_allows_song_clicks_again() -> void:
|
func test_closing_character_select_allows_song_clicks_again() -> void:
|
||||||
var character_select: PopupWindow = _popup("NewCharacterSelect")
|
var character_select: PopupWindow = _popup("NewCharacterSelect")
|
||||||
character_select.show_grid("Crono")
|
character_select.show_grid("Crono")
|
||||||
assert_bool(Settings.character_select_open).is_true()
|
assert_bool(Settings.character_select_open).is_true()
|
||||||
|
|
||||||
character_select.close()
|
character_select.close()
|
||||||
|
|
||||||
assert_bool(Settings.character_select_open).is_false()
|
assert_bool(Settings.character_select_open).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_toggle_opens_and_closes() -> void:
|
func test_toggle_opens_and_closes() -> void:
|
||||||
var shortcuts: PopupWindow = _popup("ShortcutsWindow")
|
var shortcuts: PopupWindow = _popup("ShortcutsWindow")
|
||||||
|
|
||||||
shortcuts.toggle()
|
shortcuts.toggle()
|
||||||
assert_bool(shortcuts.visible).is_true()
|
assert_bool(shortcuts.visible).is_true()
|
||||||
|
|
||||||
shortcuts.toggle()
|
shortcuts.toggle()
|
||||||
assert_bool(shortcuts.visible).is_false()
|
assert_bool(shortcuts.visible).is_false()
|
||||||
@@ -5,239 +5,239 @@ extends MainWindowTestSuite
|
|||||||
## server and the keyboard shortcuts reach both the main window and the quiz.
|
## server and the keyboard shortcuts reach both the main window and the quiz.
|
||||||
|
|
||||||
const MAIN_WINDOW_CHILDREN: Array[String] = [
|
const MAIN_WINDOW_CHILDREN: Array[String] = [
|
||||||
"TopBar", "Quiz", "PopupBackdrop", "Search", "SyncWindow", "QRWindow",
|
"TopBar", "Quiz", "PopupBackdrop", "Search", "SyncWindow", "QRWindow",
|
||||||
"ShortcutsWindow", "StatisticsPopupPanel", "AboutWindow",
|
"ShortcutsWindow", "StatisticsPopupPanel", "AboutWindow",
|
||||||
]
|
]
|
||||||
|
|
||||||
const TOP_BAR_CHILDREN: Array[String] = [
|
const TOP_BAR_CHILDREN: Array[String] = [
|
||||||
"TopPanelContainer", "Title", "SyncButton", "SearchButton", "StatisticsButton",
|
"TopPanelContainer", "Title", "SyncButton", "SearchButton", "StatisticsButton",
|
||||||
"ShortcutsButton", "AboutButton", "QRButton",
|
"ShortcutsButton", "AboutButton", "QRButton",
|
||||||
]
|
]
|
||||||
|
|
||||||
## Each top bar button and the popup it opens in the main window.
|
## Each top bar button and the popup it opens in the main window.
|
||||||
const TOP_BAR_POPUPS: Dictionary = {
|
const TOP_BAR_POPUPS: Dictionary = {
|
||||||
"SearchButton": "Search",
|
"SearchButton": "Search",
|
||||||
"SyncButton": "SyncWindow",
|
"SyncButton": "SyncWindow",
|
||||||
"StatisticsButton": "StatisticsPopupPanel",
|
"StatisticsButton": "StatisticsPopupPanel",
|
||||||
"ShortcutsButton": "ShortcutsWindow",
|
"ShortcutsButton": "ShortcutsWindow",
|
||||||
"AboutButton": "AboutWindow",
|
"AboutButton": "AboutWindow",
|
||||||
"QRButton": "QRWindow",
|
"QRButton": "QRWindow",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func _top_bar_button(button_name: String) -> Button:
|
func _top_bar_button(button_name: String) -> Button:
|
||||||
return _window.get_node("TopBar/" + button_name)
|
return _window.get_node("TopBar/" + button_name)
|
||||||
|
|
||||||
|
|
||||||
func _children(node: Node) -> Array[String]:
|
func _children(node: Node) -> Array[String]:
|
||||||
var names: Array[String] = []
|
var names: Array[String] = []
|
||||||
for child: Node in node.get_children():
|
for child: Node in node.get_children():
|
||||||
names.append(String(child.name))
|
names.append(String(child.name))
|
||||||
return names
|
return names
|
||||||
|
|
||||||
|
|
||||||
func _center(control: Control) -> Vector2:
|
func _center(control: Control) -> Vector2:
|
||||||
return control.get_global_rect().get_center()
|
return control.get_global_rect().get_center()
|
||||||
|
|
||||||
|
|
||||||
func test_main_window_holds_only_top_bar_quiz_and_its_popups() -> void:
|
func test_main_window_holds_only_top_bar_quiz_and_its_popups() -> void:
|
||||||
assert_array(_children(_window)).contains_exactly_in_any_order(MAIN_WINDOW_CHILDREN)
|
assert_array(_children(_window)).contains_exactly_in_any_order(MAIN_WINDOW_CHILDREN)
|
||||||
|
|
||||||
|
|
||||||
func test_top_bar_is_drawn_below_the_quiz() -> void:
|
func test_top_bar_is_drawn_below_the_quiz() -> void:
|
||||||
# The quiz popups' backdrop has to cover the top bar too
|
# The quiz popups' backdrop has to cover the top bar too
|
||||||
assert_int(_window.get_node("TopBar").get_index()) \
|
assert_int(_window.get_node("TopBar").get_index()) \
|
||||||
.is_less(_window.get_node("Quiz").get_index())
|
.is_less(_window.get_node("Quiz").get_index())
|
||||||
|
|
||||||
|
|
||||||
func test_quiz_parts_are_their_own_scenes() -> void:
|
func test_quiz_parts_are_their_own_scenes() -> void:
|
||||||
for node_name: String in ["MusicListPanel", "PlayersPanel", "InspirationList"]:
|
for node_name: String in ["MusicListPanel", "PlayersPanel", "InspirationList"]:
|
||||||
assert_str(_quiz.get_node(node_name).scene_file_path) \
|
assert_str(_quiz.get_node(node_name).scene_file_path) \
|
||||||
.is_equal("res://%s.tscn" % node_name)
|
.is_equal("res://%s.tscn" % node_name)
|
||||||
|
|
||||||
|
|
||||||
func test_top_bar_holds_only_title_and_buttons() -> void:
|
func test_top_bar_holds_only_title_and_buttons() -> void:
|
||||||
assert_array(_children(_window.get_node("TopBar"))) \
|
assert_array(_children(_window.get_node("TopBar"))) \
|
||||||
.contains_exactly_in_any_order(TOP_BAR_CHILDREN)
|
.contains_exactly_in_any_order(TOP_BAR_CHILDREN)
|
||||||
|
|
||||||
|
|
||||||
func test_quiz_and_top_bar_let_clicks_through_where_they_are_empty() -> void:
|
func test_quiz_and_top_bar_let_clicks_through_where_they_are_empty() -> void:
|
||||||
assert_int(_quiz.mouse_filter).is_equal(Control.MOUSE_FILTER_IGNORE)
|
assert_int(_quiz.mouse_filter).is_equal(Control.MOUSE_FILTER_IGNORE)
|
||||||
assert_int((_window.get_node("TopBar") as Control).mouse_filter) \
|
assert_int((_window.get_node("TopBar") as Control).mouse_filter) \
|
||||||
.is_equal(Control.MOUSE_FILTER_IGNORE)
|
.is_equal(Control.MOUSE_FILTER_IGNORE)
|
||||||
|
|
||||||
|
|
||||||
func test_clicking_each_top_bar_button_opens_its_popup() -> void:
|
func test_clicking_each_top_bar_button_opens_its_popup() -> void:
|
||||||
for button_name: String in TOP_BAR_POPUPS:
|
for button_name: String in TOP_BAR_POPUPS:
|
||||||
var popup: Node = _window.get_node(TOP_BAR_POPUPS[button_name])
|
var popup: Node = _window.get_node(TOP_BAR_POPUPS[button_name])
|
||||||
|
|
||||||
await _click_at(_center(_top_bar_button(button_name)))
|
await _click_at(_center(_top_bar_button(button_name)))
|
||||||
|
|
||||||
assert_bool(popup.visible).override_failure_message(
|
assert_bool(popup.visible).override_failure_message(
|
||||||
"%s did not open %s" % [button_name, popup.name]).is_true()
|
"%s did not open %s" % [button_name, popup.name]).is_true()
|
||||||
if popup is PopupWindow:
|
if popup is PopupWindow:
|
||||||
popup.close()
|
popup.close()
|
||||||
else:
|
else:
|
||||||
popup.visible = false
|
popup.visible = false
|
||||||
await _runner.simulate_frames(1)
|
await _runner.simulate_frames(1)
|
||||||
|
|
||||||
|
|
||||||
func test_clicking_quiz_buttons_plays_and_shows_answer() -> void:
|
func test_clicking_quiz_buttons_plays_and_shows_answer() -> void:
|
||||||
await _click_at(_center(_quiz.get_node("NextButton")))
|
await _click_at(_center(_quiz.get_node("NextButton")))
|
||||||
await _runner.simulate_frames(2)
|
await _runner.simulate_frames(2)
|
||||||
assert_int(Playlist.currently_playing_song).is_equal(0)
|
assert_int(Playlist.currently_playing_song).is_equal(0)
|
||||||
assert_str((_quiz.get_node("VBoxContainer/SoundtrackLabel") as Label).text) \
|
assert_str((_quiz.get_node("VBoxContainer/SoundtrackLabel") as Label).text) \
|
||||||
.is_not_equal("Chrono Trigger")
|
.is_not_equal("Chrono Trigger")
|
||||||
|
|
||||||
await _click_at(_center(_quiz.get_node("ShowAnswerButton")))
|
await _click_at(_center(_quiz.get_node("ShowAnswerButton")))
|
||||||
|
|
||||||
assert_str((_quiz.get_node("VBoxContainer/SoundtrackLabel") as Label).text) \
|
assert_str((_quiz.get_node("VBoxContainer/SoundtrackLabel") as Label).text) \
|
||||||
.is_equal("Chrono Trigger")
|
.is_equal("Chrono Trigger")
|
||||||
|
|
||||||
|
|
||||||
func test_clicking_a_song_in_the_music_list_plays_it() -> void:
|
func test_clicking_a_song_in_the_music_list_plays_it() -> void:
|
||||||
_next_song_is(SONG_INFO[1])
|
_next_song_is(SONG_INFO[1])
|
||||||
await _play_first_song()
|
await _play_first_song()
|
||||||
_press("NextButton")
|
_press("NextButton")
|
||||||
# Changing song waits a moment for the old one to stop
|
# Changing song waits a moment for the old one to stop
|
||||||
await get_tree().create_timer(0.7).timeout
|
await get_tree().create_timer(0.7).timeout
|
||||||
assert_int(Playlist.currently_playing_song).is_equal(1)
|
assert_int(Playlist.currently_playing_song).is_equal(1)
|
||||||
var rows: Array[Node] = _quiz.get_node("MusicListPanel/ScrollContainer/MusicList") \
|
var rows: Array[Node] = _quiz.get_node("MusicListPanel/ScrollContainer/MusicList") \
|
||||||
.get_children()
|
.get_children()
|
||||||
var first_row: Control = rows.filter(
|
var first_row: Control = rows.filter(
|
||||||
func(row: SongListObject) -> bool: return row.song_object.song_number == 0)[0]
|
func(row: SongListObject) -> bool: return row.song_object.song_number == 0)[0]
|
||||||
|
|
||||||
await _click_at(first_row.get_global_rect().position + Vector2(20, first_row.size.y / 2))
|
await _click_at(first_row.get_global_rect().position + Vector2(20, first_row.size.y / 2))
|
||||||
await get_tree().create_timer(0.7).timeout
|
await get_tree().create_timer(0.7).timeout
|
||||||
|
|
||||||
assert_int(Playlist.currently_playing_song).is_equal(0)
|
assert_int(Playlist.currently_playing_song).is_equal(0)
|
||||||
|
|
||||||
|
|
||||||
func test_points_from_the_player_list_reach_the_song_and_log() -> void:
|
func test_points_from_the_player_list_reach_the_song_and_log() -> void:
|
||||||
await _play_first_song()
|
await _play_first_song()
|
||||||
var crono: PlayerObject = _add_player("Crono")
|
var crono: PlayerObject = _add_player("Crono")
|
||||||
|
|
||||||
(_player_row(crono).get_node("HBoxContainer/AddPoint") as BaseButton).pressed.emit()
|
(_player_row(crono).get_node("HBoxContainer/AddPoint") as BaseButton).pressed.emit()
|
||||||
|
|
||||||
assert_array(Playlist.song_object_array[0].players_given_point).contains_exactly([crono.id])
|
assert_array(Playlist.song_object_array[0].players_given_point).contains_exactly([crono.id])
|
||||||
assert_int((_quiz.get_node("%Log").get_node("%LogVBoxContainer") as Node).get_child_count()) \
|
assert_int((_quiz.get_node("%Log").get_node("%LogVBoxContainer") as Node).get_child_count()) \
|
||||||
.is_equal(1)
|
.is_equal(1)
|
||||||
|
|
||||||
|
|
||||||
func test_character_button_in_the_player_list_picks_a_new_character() -> void:
|
func test_character_button_in_the_player_list_picks_a_new_character() -> void:
|
||||||
var crono: PlayerObject = _add_player("Crono")
|
var crono: PlayerObject = _add_player("Crono")
|
||||||
var character_select: PopupWindow = _quiz.get_node("NewCharacterSelect")
|
var character_select: PopupWindow = _quiz.get_node("NewCharacterSelect")
|
||||||
|
|
||||||
(_player_row(crono).get_node("HBoxContainer/Character") as BaseButton).pressed.emit()
|
(_player_row(crono).get_node("HBoxContainer/Character") as BaseButton).pressed.emit()
|
||||||
|
|
||||||
assert_bool(character_select.visible).is_true()
|
assert_bool(character_select.visible).is_true()
|
||||||
var texture: ImageTexture = ImageTexture.create_from_image(
|
var texture: ImageTexture = ImageTexture.create_from_image(
|
||||||
Image.create(4, 4, false, Image.FORMAT_RGBA8))
|
Image.create(4, 4, false, Image.FORMAT_RGBA8))
|
||||||
character_select.new_new_character_selected.emit(texture)
|
character_select.new_new_character_selected.emit(texture)
|
||||||
assert_object(crono.character).is_same(texture)
|
assert_object(crono.character).is_same(texture)
|
||||||
|
|
||||||
|
|
||||||
func test_quiz_popup_backdrop_covers_the_top_bar() -> void:
|
func test_quiz_popup_backdrop_covers_the_top_bar() -> void:
|
||||||
var settings: PopupWindow = _quiz.get_node("SettingsWindow")
|
var settings: PopupWindow = _quiz.get_node("SettingsWindow")
|
||||||
settings.open()
|
settings.open()
|
||||||
await _runner.simulate_frames(1)
|
await _runner.simulate_frames(1)
|
||||||
|
|
||||||
var backdrop: Control = _quiz.get_node("PopupBackdrop")
|
var backdrop: Control = _quiz.get_node("PopupBackdrop")
|
||||||
assert_bool(backdrop.visible).is_true()
|
assert_bool(backdrop.visible).is_true()
|
||||||
assert_bool(backdrop.get_global_rect().encloses(
|
assert_bool(backdrop.get_global_rect().encloses(
|
||||||
(_window.get_node("TopBar/TopPanelContainer") as Control).get_global_rect())) \
|
(_window.get_node("TopBar/TopPanelContainer") as Control).get_global_rect())) \
|
||||||
.is_true()
|
.is_true()
|
||||||
|
|
||||||
|
|
||||||
func test_click_on_top_bar_while_quiz_popup_is_open_only_closes_it() -> void:
|
func test_click_on_top_bar_while_quiz_popup_is_open_only_closes_it() -> void:
|
||||||
var settings: PopupWindow = _quiz.get_node("SettingsWindow")
|
var settings: PopupWindow = _quiz.get_node("SettingsWindow")
|
||||||
var search: PopupWindow = _window.get_node("Search")
|
var search: PopupWindow = _window.get_node("Search")
|
||||||
settings.open()
|
settings.open()
|
||||||
await _runner.simulate_frames(1)
|
await _runner.simulate_frames(1)
|
||||||
|
|
||||||
await _click_at(_center(_top_bar_button("SearchButton")))
|
await _click_at(_center(_top_bar_button("SearchButton")))
|
||||||
|
|
||||||
assert_bool(settings.visible).is_false()
|
assert_bool(settings.visible).is_false()
|
||||||
assert_bool(search.visible).is_false()
|
assert_bool(search.visible).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_sync_disables_quiz_buttons_until_finished() -> void:
|
func test_sync_disables_quiz_buttons_until_finished() -> void:
|
||||||
_server.respond_bytes("/sync", PackedByteArray())
|
_server.respond_bytes("/sync", PackedByteArray())
|
||||||
_server.respond_json("/sync/progress", {"progress": 10, "time_spent": "00:00:01"})
|
_server.respond_json("/sync/progress", {"progress": 10, "time_spent": "00:00:01"})
|
||||||
var sync_window: PopupWindow = _window.get_node("SyncWindow")
|
var sync_window: PopupWindow = _window.get_node("SyncWindow")
|
||||||
|
|
||||||
_top_bar_button("SyncButton").pressed.emit()
|
_top_bar_button("SyncButton").pressed.emit()
|
||||||
sync_window.sync_timer.stop()
|
sync_window.sync_timer.stop()
|
||||||
|
|
||||||
for button_name: String in ["SoundTestButton", "ResetPlaylistButton", "ShowAnswerButton",
|
for button_name: String in ["SoundTestButton", "ResetPlaylistButton", "ShowAnswerButton",
|
||||||
"NextButton"]:
|
"NextButton"]:
|
||||||
assert_bool((_quiz.get_node(button_name) as Button).disabled) \
|
assert_bool((_quiz.get_node(button_name) as Button).disabled) \
|
||||||
.override_failure_message(button_name + " not disabled").is_true()
|
.override_failure_message(button_name + " not disabled").is_true()
|
||||||
assert_bool(_top_bar_button("SyncButton").disabled).is_false()
|
assert_bool(_top_bar_button("SyncButton").disabled).is_false()
|
||||||
|
|
||||||
_server.respond_json("/sync/progress", UiTour.SYNC_RESULT)
|
_server.respond_json("/sync/progress", UiTour.SYNC_RESULT)
|
||||||
var reloads_before: int = _server.count("/music/all/order")
|
var reloads_before: int = _server.count("/music/all/order")
|
||||||
sync_window._on_sync_timeout()
|
sync_window._on_sync_timeout()
|
||||||
await _runner.simulate_frames(2)
|
await _runner.simulate_frames(2)
|
||||||
|
|
||||||
for button_name: String in ["SoundTestButton", "ResetPlaylistButton", "ShowAnswerButton",
|
for button_name: String in ["SoundTestButton", "ResetPlaylistButton", "ShowAnswerButton",
|
||||||
"NextButton"]:
|
"NextButton"]:
|
||||||
assert_bool((_quiz.get_node(button_name) as Button).disabled) \
|
assert_bool((_quiz.get_node(button_name) as Button).disabled) \
|
||||||
.override_failure_message(button_name + " still disabled").is_false()
|
.override_failure_message(button_name + " still disabled").is_false()
|
||||||
# The search list in the main window and the quiz playlist are both reloaded
|
# The search list in the main window and the quiz playlist are both reloaded
|
||||||
assert_int(_server.count("/music/all/order")).is_equal(reloads_before + 1)
|
assert_int(_server.count("/music/all/order")).is_equal(reloads_before + 1)
|
||||||
assert_int(_server.count("/music/reset")).is_equal(1)
|
assert_int(_server.count("/music/reset")).is_equal(1)
|
||||||
|
|
||||||
|
|
||||||
func test_changing_server_reloads_search_and_quiz() -> void:
|
func test_changing_server_reloads_search_and_quiz() -> void:
|
||||||
var search_loads: int = _server.count("/music/all/order")
|
var search_loads: int = _server.count("/music/all/order")
|
||||||
var inspiration_loads: int = _server.count("/music/all")
|
var inspiration_loads: int = _server.count("/music/all")
|
||||||
var player: PlayerObject = _add_player("Crono")
|
var player: PlayerObject = _add_player("Crono")
|
||||||
player.add_point()
|
player.add_point()
|
||||||
|
|
||||||
_quiz.get_node("SettingsWindow").server_changed.emit()
|
_quiz.get_node("SettingsWindow").server_changed.emit()
|
||||||
|
|
||||||
assert_int(_server.count("/music/all/order")).is_equal(search_loads + 1)
|
assert_int(_server.count("/music/all/order")).is_equal(search_loads + 1)
|
||||||
assert_int(_server.count("/music/all")).is_equal(inspiration_loads + 1)
|
assert_int(_server.count("/music/all")).is_equal(inspiration_loads + 1)
|
||||||
assert_int(_server.count("/music/reset")).is_equal(1)
|
assert_int(_server.count("/music/reset")).is_equal(1)
|
||||||
assert_int(player.player_score).is_equal(0)
|
assert_int(player.player_score).is_equal(0)
|
||||||
|
|
||||||
|
|
||||||
func test_alt_k_opens_shortcuts_and_alt_l_opens_log() -> void:
|
func test_alt_k_opens_shortcuts_and_alt_l_opens_log() -> void:
|
||||||
await _press_keys([KEY_ALT, KEY_K])
|
await _press_keys([KEY_ALT, KEY_K])
|
||||||
assert_bool((_window.get_node("ShortcutsWindow") as Control).visible).is_true()
|
assert_bool((_window.get_node("ShortcutsWindow") as Control).visible).is_true()
|
||||||
|
|
||||||
await _press_keys([KEY_ALT, KEY_L])
|
await _press_keys([KEY_ALT, KEY_L])
|
||||||
assert_bool((_quiz.get_node("Log") as Control).visible).is_true()
|
assert_bool((_quiz.get_node("Log") as Control).visible).is_true()
|
||||||
|
|
||||||
|
|
||||||
func test_alt_down_lowers_the_volume() -> void:
|
func test_alt_down_lowers_the_volume() -> void:
|
||||||
var bus: int = AudioServer.get_bus_index("Master")
|
var bus: int = AudioServer.get_bus_index("Master")
|
||||||
var volume_db: float = AudioServer.get_bus_volume_db(bus)
|
var volume_db: float = AudioServer.get_bus_volume_db(bus)
|
||||||
var slider: HSlider = _quiz.get_node("MusicPlayer").volume_slider
|
var slider: HSlider = _quiz.get_node("MusicPlayer").volume_slider
|
||||||
var volume: float = slider.value
|
var volume: float = slider.value
|
||||||
|
|
||||||
await _press_keys([KEY_ALT, KEY_DOWN])
|
await _press_keys([KEY_ALT, KEY_DOWN])
|
||||||
|
|
||||||
assert_float(slider.value).is_less(volume)
|
assert_float(slider.value).is_less(volume)
|
||||||
AudioServer.set_bus_volume_db(bus, volume_db)
|
AudioServer.set_bus_volume_db(bus, volume_db)
|
||||||
|
|
||||||
|
|
||||||
func test_alt_enter_switches_fullscreen_and_settings_shows_it() -> void:
|
func test_alt_enter_switches_fullscreen_and_settings_shows_it() -> void:
|
||||||
var settings: PopupWindow = _quiz.get_node("SettingsWindow")
|
var settings: PopupWindow = _quiz.get_node("SettingsWindow")
|
||||||
var was_fullscreen: bool = Settings.fullscreen
|
var was_fullscreen: bool = Settings.fullscreen
|
||||||
|
|
||||||
await _press_keys([KEY_ALT, KEY_ENTER])
|
await _press_keys([KEY_ALT, KEY_ENTER])
|
||||||
settings.open()
|
settings.open()
|
||||||
|
|
||||||
assert_bool(Settings.fullscreen).is_equal(!was_fullscreen)
|
assert_bool(Settings.fullscreen).is_equal(!was_fullscreen)
|
||||||
assert_bool(settings.fullscreen_button.button_pressed).is_equal(!was_fullscreen)
|
assert_bool(settings.fullscreen_button.button_pressed).is_equal(!was_fullscreen)
|
||||||
await _press_keys([KEY_ALT, KEY_ENTER])
|
await _press_keys([KEY_ALT, KEY_ENTER])
|
||||||
assert_bool(Settings.fullscreen).is_equal(was_fullscreen)
|
assert_bool(Settings.fullscreen).is_equal(was_fullscreen)
|
||||||
|
|
||||||
|
|
||||||
func test_statistics_counts_the_soundtracks() -> void:
|
func test_statistics_counts_the_soundtracks() -> void:
|
||||||
_top_bar_button("StatisticsButton").pressed.emit()
|
_top_bar_button("StatisticsButton").pressed.emit()
|
||||||
|
|
||||||
assert_str((_window.get_node("StatisticsPopupPanel/StatisticsLabel") as Label).text) \
|
assert_str((_window.get_node("StatisticsPopupPanel/StatisticsLabel") as Label).text) \
|
||||||
.is_equal("Total amount of soundtracks in the playlist: 2")
|
.is_equal("Total amount of soundtracks in the playlist: 2")
|
||||||
@@ -5,61 +5,61 @@ var _crono: PlayerObject
|
|||||||
|
|
||||||
|
|
||||||
func before_test() -> void:
|
func before_test() -> void:
|
||||||
super()
|
super()
|
||||||
_crono = _add_player("Crono")
|
_crono = _add_player("Crono")
|
||||||
await _play_first_song()
|
await _play_first_song()
|
||||||
Settings.winning_score = 1
|
Settings.winning_score = 1
|
||||||
|
|
||||||
|
|
||||||
func _stats_checkbox() -> CheckButton:
|
func _stats_checkbox() -> CheckButton:
|
||||||
return _quiz.get_node("SettingsWindow").get_node("%AddToDatabaseCheckButton")
|
return _quiz.get_node("SettingsWindow").get_node("%AddToDatabaseCheckButton")
|
||||||
|
|
||||||
|
|
||||||
func test_winning_turns_statistics_off() -> void:
|
func test_winning_turns_statistics_off() -> void:
|
||||||
await _give_point_with_keybind(1)
|
await _give_point_with_keybind(1)
|
||||||
|
|
||||||
assert_bool(Settings.add_to_stats).is_false()
|
assert_bool(Settings.add_to_stats).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_resetting_points_turns_statistics_back_on() -> void:
|
func test_resetting_points_turns_statistics_back_on() -> void:
|
||||||
await _give_point_with_keybind(1)
|
await _give_point_with_keybind(1)
|
||||||
|
|
||||||
_press("ResetPointsButton")
|
_press("ResetPointsButton")
|
||||||
|
|
||||||
assert_bool(Settings.add_to_stats).is_true()
|
assert_bool(Settings.add_to_stats).is_true()
|
||||||
|
|
||||||
|
|
||||||
func test_statistics_turned_off_by_hand_stay_off_after_reset() -> void:
|
func test_statistics_turned_off_by_hand_stay_off_after_reset() -> void:
|
||||||
Settings.add_to_stats = false
|
Settings.add_to_stats = false
|
||||||
await _give_point_with_keybind(1)
|
await _give_point_with_keybind(1)
|
||||||
|
|
||||||
_press("ResetPointsButton")
|
_press("ResetPointsButton")
|
||||||
|
|
||||||
assert_bool(Settings.add_to_stats).is_false()
|
assert_bool(Settings.add_to_stats).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_settings_checkbox_shows_statistics_off_after_win() -> void:
|
func test_settings_checkbox_shows_statistics_off_after_win() -> void:
|
||||||
await _give_point_with_keybind(1)
|
await _give_point_with_keybind(1)
|
||||||
|
|
||||||
_press("SettingsButton")
|
_press("SettingsButton")
|
||||||
|
|
||||||
assert_bool(_stats_checkbox().button_pressed).is_false()
|
assert_bool(_stats_checkbox().button_pressed).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_songs_after_a_win_are_not_counted() -> void:
|
func test_songs_after_a_win_are_not_counted() -> void:
|
||||||
await _give_point_with_keybind(1)
|
await _give_point_with_keybind(1)
|
||||||
var played_before: int = _server.count("/music/played?song=0")
|
var played_before: int = _server.count("/music/played?song=0")
|
||||||
|
|
||||||
_press("ShowAnswerButton")
|
_press("ShowAnswerButton")
|
||||||
|
|
||||||
assert_int(_server.count("/music/played?song=0")).is_equal(played_before)
|
assert_int(_server.count("/music/played?song=0")).is_equal(played_before)
|
||||||
|
|
||||||
|
|
||||||
func test_winning_score_cannot_go_below_one() -> void:
|
func test_winning_score_cannot_go_below_one() -> void:
|
||||||
_press("SettingsButton")
|
_press("SettingsButton")
|
||||||
var lower_button: Button = _quiz.get_node("SettingsWindow").get_node("%LowerButton")
|
var lower_button: Button = _quiz.get_node("SettingsWindow").get_node("%LowerButton")
|
||||||
|
|
||||||
for i: int in 3:
|
for i: int in 3:
|
||||||
lower_button.pressed.emit()
|
lower_button.pressed.emit()
|
||||||
|
|
||||||
assert_int(Settings.winning_score).is_equal(1)
|
assert_int(Settings.winning_score).is_equal(1)
|
||||||
@@ -7,194 +7,194 @@ var _window: Control
|
|||||||
|
|
||||||
|
|
||||||
func before_test() -> void:
|
func before_test() -> void:
|
||||||
_snapshot = AutoloadSnapshot.take([Settings])
|
_snapshot = AutoloadSnapshot.take([Settings])
|
||||||
Settings.currently_syncing = false
|
Settings.currently_syncing = false
|
||||||
_server = FakeHttpTransport.new().install()
|
_server = FakeHttpTransport.new().install()
|
||||||
_server.respond_bytes("/sync", PackedByteArray())
|
_server.respond_bytes("/sync", PackedByteArray())
|
||||||
_runner = scene_runner("res://SyncWindow.tscn")
|
_runner = scene_runner("res://SyncWindow.tscn")
|
||||||
_window = _runner.scene()
|
_window = _runner.scene()
|
||||||
|
|
||||||
|
|
||||||
func after_test() -> void:
|
func after_test() -> void:
|
||||||
_server.uninstall()
|
_server.uninstall()
|
||||||
_snapshot.restore()
|
_snapshot.restore()
|
||||||
|
|
||||||
|
|
||||||
func _node(unique_name: String) -> Control:
|
func _node(unique_name: String) -> Control:
|
||||||
return _window.get_node("%" + unique_name)
|
return _window.get_node("%" + unique_name)
|
||||||
|
|
||||||
|
|
||||||
func _finish_sync(result: Dictionary) -> void:
|
func _finish_sync(result: Dictionary) -> void:
|
||||||
_server.respond_json("/sync/progress", result)
|
_server.respond_json("/sync/progress", result)
|
||||||
_runner.invoke("_on_sync_timeout")
|
_runner.invoke("_on_sync_timeout")
|
||||||
|
|
||||||
|
|
||||||
func _empty_result() -> Dictionary:
|
func _empty_result() -> Dictionary:
|
||||||
return {
|
return {
|
||||||
"soundtracks_added": [],
|
"soundtracks_added": [],
|
||||||
"soundtracks_re_added": [],
|
"soundtracks_re_added": [],
|
||||||
"soundtracks_changed_title": {},
|
"soundtracks_changed_title": {},
|
||||||
"soundtracks_changed_content": [],
|
"soundtracks_changed_content": [],
|
||||||
"soundtracks_removed": [],
|
"soundtracks_removed": [],
|
||||||
"catched_errors": [],
|
"catched_errors": [],
|
||||||
"total_time": "00:00:03",
|
"total_time": "00:00:03",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func test_start_sync_asks_server_and_shows_progress() -> void:
|
func test_start_sync_asks_server_and_shows_progress() -> void:
|
||||||
monitor_signals(_window, false)
|
monitor_signals(_window, false)
|
||||||
|
|
||||||
_runner.invoke("start_sync")
|
_runner.invoke("start_sync")
|
||||||
|
|
||||||
assert_array(_server.requested_paths).contains_exactly(["/sync"])
|
assert_array(_server.requested_paths).contains_exactly(["/sync"])
|
||||||
assert_bool(Settings.currently_syncing).is_true()
|
assert_bool(Settings.currently_syncing).is_true()
|
||||||
assert_bool(_node("ProgressHBoxContainer").visible).is_true()
|
assert_bool(_node("ProgressHBoxContainer").visible).is_true()
|
||||||
assert_str(_node("SyncTitleLabel").text).is_equal("Sync in Progress")
|
assert_str(_node("SyncTitleLabel").text).is_equal("Sync in Progress")
|
||||||
await assert_signal(_window).is_emitted("sync_started")
|
await assert_signal(_window).is_emitted("sync_started")
|
||||||
|
|
||||||
|
|
||||||
func test_start_sync_does_nothing_while_already_syncing() -> void:
|
func test_start_sync_does_nothing_while_already_syncing() -> void:
|
||||||
Settings.currently_syncing = true
|
Settings.currently_syncing = true
|
||||||
|
|
||||||
_runner.invoke("start_sync")
|
_runner.invoke("start_sync")
|
||||||
|
|
||||||
assert_array(_server.requested_paths).is_empty()
|
assert_array(_server.requested_paths).is_empty()
|
||||||
|
|
||||||
|
|
||||||
func test_progress_updates_progress_bar() -> void:
|
func test_progress_updates_progress_bar() -> void:
|
||||||
_runner.invoke("start_sync")
|
_runner.invoke("start_sync")
|
||||||
_server.respond_json("/sync/progress", {"progress": "42", "time_spent": "00:00:12"})
|
_server.respond_json("/sync/progress", {"progress": "42", "time_spent": "00:00:12"})
|
||||||
|
|
||||||
_runner.invoke("_on_sync_timeout")
|
_runner.invoke("_on_sync_timeout")
|
||||||
|
|
||||||
assert_float(_node("SyncProgressBar").value).is_equal(42.0)
|
assert_float(_node("SyncProgressBar").value).is_equal(42.0)
|
||||||
assert_str(_node("SyncTime").text).is_equal("00:00:12")
|
assert_str(_node("SyncTime").text).is_equal("00:00:12")
|
||||||
|
|
||||||
|
|
||||||
func test_finished_sync_shows_only_sections_with_changes() -> void:
|
func test_finished_sync_shows_only_sections_with_changes() -> void:
|
||||||
_runner.invoke("start_sync")
|
_runner.invoke("start_sync")
|
||||||
monitor_signals(_window, false)
|
monitor_signals(_window, false)
|
||||||
var result: Dictionary = _empty_result()
|
var result: Dictionary = _empty_result()
|
||||||
result.soundtracks_added = ["Chrono Cross", "Xenogears"]
|
result.soundtracks_added = ["Chrono Cross", "Xenogears"]
|
||||||
result.soundtracks_removed = ["Bad Rip"]
|
result.soundtracks_removed = ["Bad Rip"]
|
||||||
|
|
||||||
_finish_sync(result)
|
_finish_sync(result)
|
||||||
|
|
||||||
assert_bool(_node("SoundtracksAddedVBox").visible).is_true()
|
assert_bool(_node("SoundtracksAddedVBox").visible).is_true()
|
||||||
assert_bool(_node("SoundtracksRemovedVBox").visible).is_true()
|
assert_bool(_node("SoundtracksRemovedVBox").visible).is_true()
|
||||||
assert_bool(_node("SoundtracksReAddedVBox").visible).is_false()
|
assert_bool(_node("SoundtracksReAddedVBox").visible).is_false()
|
||||||
assert_bool(_node("SoundtracksChangedTitleVBox").visible).is_false()
|
assert_bool(_node("SoundtracksChangedTitleVBox").visible).is_false()
|
||||||
assert_bool(_node("NoChangesLabel").visible).is_false()
|
assert_bool(_node("NoChangesLabel").visible).is_false()
|
||||||
# Header plus one label per soundtrack
|
# Header plus one label per soundtrack
|
||||||
assert_int(_node("SoundtracksAddedVBox").get_child_count()).is_equal(3)
|
assert_int(_node("SoundtracksAddedVBox").get_child_count()).is_equal(3)
|
||||||
assert_str(_node("SyncTime").text).is_equal("Total time: 00:00:03")
|
assert_str(_node("SyncTime").text).is_equal("Total time: 00:00:03")
|
||||||
assert_bool(Settings.currently_syncing).is_false()
|
assert_bool(Settings.currently_syncing).is_false()
|
||||||
await assert_signal(_window).is_emitted("sync_finished")
|
await assert_signal(_window).is_emitted("sync_finished")
|
||||||
|
|
||||||
|
|
||||||
func test_separator_shown_only_between_visible_sections() -> void:
|
func test_separator_shown_only_between_visible_sections() -> void:
|
||||||
_runner.invoke("start_sync")
|
_runner.invoke("start_sync")
|
||||||
var result: Dictionary = _empty_result()
|
var result: Dictionary = _empty_result()
|
||||||
result.soundtracks_added = ["Chrono Cross"]
|
result.soundtracks_added = ["Chrono Cross"]
|
||||||
result.soundtracks_removed = ["Bad Rip"]
|
result.soundtracks_removed = ["Bad Rip"]
|
||||||
|
|
||||||
_finish_sync(result)
|
_finish_sync(result)
|
||||||
|
|
||||||
assert_bool(_node("SoundtracksAddedSeparator").visible).is_true()
|
assert_bool(_node("SoundtracksAddedSeparator").visible).is_true()
|
||||||
assert_bool(_node("SoundtracksRemovedSeparator").visible).is_false()
|
assert_bool(_node("SoundtracksRemovedSeparator").visible).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_changed_titles_list_old_and_new_title() -> void:
|
func test_changed_titles_list_old_and_new_title() -> void:
|
||||||
_runner.invoke("start_sync")
|
_runner.invoke("start_sync")
|
||||||
var result: Dictionary = _empty_result()
|
var result: Dictionary = _empty_result()
|
||||||
result.soundtracks_changed_title = {"FF7": "Final Fantasy VII"}
|
result.soundtracks_changed_title = {"FF7": "Final Fantasy VII"}
|
||||||
|
|
||||||
_finish_sync(result)
|
_finish_sync(result)
|
||||||
|
|
||||||
var vbox: Control = _node("SoundtracksChangedTitleVBox")
|
var vbox: Control = _node("SoundtracksChangedTitleVBox")
|
||||||
assert_bool(vbox.visible).is_true()
|
assert_bool(vbox.visible).is_true()
|
||||||
assert_str((vbox.get_child(1) as ListRow).text).is_equal(
|
assert_str((vbox.get_child(1) as ListRow).text).is_equal(
|
||||||
"FF7\nchanged title to\nFinal Fantasy VII")
|
"FF7\nchanged title to\nFinal Fantasy VII")
|
||||||
|
|
||||||
|
|
||||||
func test_no_changes_shows_no_changes_label() -> void:
|
func test_no_changes_shows_no_changes_label() -> void:
|
||||||
_runner.invoke("start_sync")
|
_runner.invoke("start_sync")
|
||||||
|
|
||||||
_finish_sync(_empty_result())
|
_finish_sync(_empty_result())
|
||||||
|
|
||||||
assert_bool(_node("NoChangesLabel").visible).is_true()
|
assert_bool(_node("NoChangesLabel").visible).is_true()
|
||||||
|
|
||||||
|
|
||||||
func test_errors_are_listed() -> void:
|
func test_errors_are_listed() -> void:
|
||||||
_runner.invoke("start_sync")
|
_runner.invoke("start_sync")
|
||||||
var result: Dictionary = _empty_result()
|
var result: Dictionary = _empty_result()
|
||||||
result.catched_errors = ["Could not read tags in broken.mp3"]
|
result.catched_errors = ["Could not read tags in broken.mp3"]
|
||||||
|
|
||||||
_finish_sync(result)
|
_finish_sync(result)
|
||||||
|
|
||||||
assert_bool(_node("CatchedErrorsVBox").visible).is_true()
|
assert_bool(_node("CatchedErrorsVBox").visible).is_true()
|
||||||
|
|
||||||
|
|
||||||
func test_reopening_after_sync_shows_result_without_syncing_again() -> void:
|
func test_reopening_after_sync_shows_result_without_syncing_again() -> void:
|
||||||
_runner.invoke("start_sync")
|
_runner.invoke("start_sync")
|
||||||
_finish_sync(_empty_result())
|
_finish_sync(_empty_result())
|
||||||
|
|
||||||
_runner.invoke("start_sync")
|
_runner.invoke("start_sync")
|
||||||
|
|
||||||
assert_int(_server.count("/sync")).is_equal(1)
|
assert_int(_server.count("/sync")).is_equal(1)
|
||||||
assert_str(_node("SyncTitleLabel").text).is_equal("Sync Result")
|
assert_str(_node("SyncTitleLabel").text).is_equal("Sync Result")
|
||||||
|
|
||||||
|
|
||||||
func test_errors_section_has_errors_header() -> void:
|
func test_errors_section_has_errors_header() -> void:
|
||||||
_runner.invoke("start_sync")
|
_runner.invoke("start_sync")
|
||||||
var result: Dictionary = _empty_result()
|
var result: Dictionary = _empty_result()
|
||||||
result.catched_errors = ["Could not read tags in broken.mp3"]
|
result.catched_errors = ["Could not read tags in broken.mp3"]
|
||||||
|
|
||||||
_finish_sync(result)
|
_finish_sync(result)
|
||||||
|
|
||||||
assert_str((_node("CatchedErrorsVBox").get_child(0) as Label).text).is_equal("Errors")
|
assert_str((_node("CatchedErrorsVBox").get_child(0) as Label).text).is_equal("Errors")
|
||||||
|
|
||||||
|
|
||||||
func test_long_names_wrap_instead_of_widening_the_window() -> void:
|
func test_long_names_wrap_instead_of_widening_the_window() -> void:
|
||||||
_runner.invoke("start_sync")
|
_runner.invoke("start_sync")
|
||||||
var long_name: String = "The Legend of Zelda: Breath of the Wild Original Soundtrack"
|
var long_name: String = "The Legend of Zelda: Breath of the Wild Original Soundtrack"
|
||||||
var result: Dictionary = _empty_result()
|
var result: Dictionary = _empty_result()
|
||||||
result.soundtracks_added = [long_name]
|
result.soundtracks_added = [long_name]
|
||||||
result.soundtracks_re_added = [long_name]
|
result.soundtracks_re_added = [long_name]
|
||||||
result.soundtracks_changed_content = [long_name]
|
result.soundtracks_changed_content = [long_name]
|
||||||
result.soundtracks_removed = [long_name]
|
result.soundtracks_removed = [long_name]
|
||||||
result.soundtracks_changed_title = {long_name: long_name}
|
result.soundtracks_changed_title = {long_name: long_name}
|
||||||
result.catched_errors = [long_name + " could not be read"]
|
result.catched_errors = [long_name + " could not be read"]
|
||||||
|
|
||||||
_finish_sync(result)
|
_finish_sync(result)
|
||||||
await _runner.simulate_frames(2)
|
await _runner.simulate_frames(2)
|
||||||
|
|
||||||
# The minimum width is what the content needs; wider than the panel it would stick out
|
# The minimum width is what the content needs; wider than the panel it would stick out
|
||||||
var panel_width: float = (_window.get_node("SyncPanel") as Control).size.x
|
var panel_width: float = (_window.get_node("SyncPanel") as Control).size.x
|
||||||
assert_float(_node("SyncHBoxContainer").get_combined_minimum_size().x) \
|
assert_float(_node("SyncHBoxContainer").get_combined_minimum_size().x) \
|
||||||
.is_less(panel_width)
|
.is_less(panel_width)
|
||||||
assert_float(_node("CatchedErrorsVBox").get_combined_minimum_size().x) \
|
assert_float(_node("CatchedErrorsVBox").get_combined_minimum_size().x) \
|
||||||
.is_less(panel_width)
|
.is_less(panel_width)
|
||||||
|
|
||||||
|
|
||||||
func test_visible_columns_share_the_width_equally() -> void:
|
func test_visible_columns_share_the_width_equally() -> void:
|
||||||
_runner.invoke("start_sync")
|
_runner.invoke("start_sync")
|
||||||
var result: Dictionary = _empty_result()
|
var result: Dictionary = _empty_result()
|
||||||
result.soundtracks_added = ["Chrono Cross", "Xenoblade Chronicles X Original Soundtrack"]
|
result.soundtracks_added = ["Chrono Cross", "Xenoblade Chronicles X Original Soundtrack"]
|
||||||
result.soundtracks_removed = ["Bad Rip"]
|
result.soundtracks_removed = ["Bad Rip"]
|
||||||
|
|
||||||
_finish_sync(result)
|
_finish_sync(result)
|
||||||
await _runner.simulate_frames(2)
|
await _runner.simulate_frames(2)
|
||||||
|
|
||||||
assert_float(_node("SoundtracksAddedVBox").size.x).is_equal_approx(
|
assert_float(_node("SoundtracksAddedVBox").size.x).is_equal_approx(
|
||||||
_node("SoundtracksRemovedVBox").size.x, 1.0)
|
_node("SoundtracksRemovedVBox").size.x, 1.0)
|
||||||
|
|
||||||
|
|
||||||
func test_column_headers() -> void:
|
func test_column_headers() -> void:
|
||||||
_runner.invoke("start_sync")
|
_runner.invoke("start_sync")
|
||||||
var result: Dictionary = _empty_result()
|
var result: Dictionary = _empty_result()
|
||||||
result.soundtracks_re_added = ["Super Metroid"]
|
result.soundtracks_re_added = ["Super Metroid"]
|
||||||
|
|
||||||
_finish_sync(result)
|
_finish_sync(result)
|
||||||
|
|
||||||
assert_str((_node("SoundtracksReAddedVBox").get_child(0) as Label).text).is_equal("Re-added")
|
assert_str((_node("SoundtracksReAddedVBox").get_child(0) as Label).text).is_equal("Re-added")
|
||||||
@@ -8,41 +8,41 @@ var _owner: Node
|
|||||||
|
|
||||||
|
|
||||||
func before_test() -> void:
|
func before_test() -> void:
|
||||||
_server = TCPServer.new()
|
_server = TCPServer.new()
|
||||||
assert_int(_server.listen(0, "127.0.0.1")).is_equal(OK)
|
assert_int(_server.listen(0, "127.0.0.1")).is_equal(OK)
|
||||||
_owner = auto_free(Node.new())
|
_owner = auto_free(Node.new())
|
||||||
add_child(_owner)
|
add_child(_owner)
|
||||||
|
|
||||||
|
|
||||||
func after_test() -> void:
|
func after_test() -> void:
|
||||||
for connection: StreamPeerTCP in _connections:
|
for connection: StreamPeerTCP in _connections:
|
||||||
connection.disconnect_from_host()
|
connection.disconnect_from_host()
|
||||||
_server.stop()
|
_server.stop()
|
||||||
|
|
||||||
|
|
||||||
func _accept_connections() -> void:
|
func _accept_connections() -> void:
|
||||||
while _server.is_connection_available():
|
while _server.is_connection_available():
|
||||||
_connections.append(_server.take_connection())
|
_connections.append(_server.take_connection())
|
||||||
|
|
||||||
|
|
||||||
func test_request_to_silent_server_times_out_as_failed() -> void:
|
func test_request_to_silent_server_times_out_as_failed() -> void:
|
||||||
var transport: HttpTransport = HttpTransport.new(_owner)
|
var transport: HttpTransport = HttpTransport.new(_owner)
|
||||||
transport.timeout_seconds = 0.5
|
transport.timeout_seconds = 0.5
|
||||||
var response_codes: Array[int] = []
|
var response_codes: Array[int] = []
|
||||||
|
|
||||||
transport.request("http://127.0.0.1:%d/music/rand" % _server.get_local_port(),
|
transport.request("http://127.0.0.1:%d/music/rand" % _server.get_local_port(),
|
||||||
HTTPClient.METHOD_GET,
|
HTTPClient.METHOD_GET,
|
||||||
func(response_code: int, _body: PackedByteArray) -> void:
|
func(response_code: int, _body: PackedByteArray) -> void:
|
||||||
response_codes.append(response_code))
|
response_codes.append(response_code))
|
||||||
for i: int in 40:
|
for i: int in 40:
|
||||||
_accept_connections()
|
_accept_connections()
|
||||||
await await_millis(50)
|
await await_millis(50)
|
||||||
if !response_codes.is_empty():
|
if !response_codes.is_empty():
|
||||||
break
|
break
|
||||||
|
|
||||||
assert_bool(_connections.is_empty()).is_false()
|
assert_bool(_connections.is_empty()).is_false()
|
||||||
assert_array(response_codes).contains_exactly([0])
|
assert_array(response_codes).contains_exactly([0])
|
||||||
|
|
||||||
|
|
||||||
func test_default_timeout_is_set() -> void:
|
func test_default_timeout_is_set() -> void:
|
||||||
assert_float(HttpTransport.new(_owner).timeout_seconds).is_greater(0.0)
|
assert_float(HttpTransport.new(_owner).timeout_seconds).is_greater(0.0)
|
||||||
+10
-10
@@ -2,25 +2,25 @@ extends GdUnitTestSuite
|
|||||||
|
|
||||||
|
|
||||||
func _background(list_row: ListRow) -> Color:
|
func _background(list_row: ListRow) -> Color:
|
||||||
return (list_row.get_theme_stylebox("panel") as StyleBoxFlat).bg_color
|
return (list_row.get_theme_stylebox("panel") as StyleBoxFlat).bg_color
|
||||||
|
|
||||||
|
|
||||||
func test_row_shows_text() -> void:
|
func test_row_shows_text() -> void:
|
||||||
var list_row: ListRow = auto_free(ListRow.create("Chrono Trigger", 0, 20))
|
var list_row: ListRow = auto_free(ListRow.create("Chrono Trigger", 0, 20))
|
||||||
|
|
||||||
assert_str(list_row.text).is_equal("Chrono Trigger")
|
assert_str(list_row.text).is_equal("Chrono Trigger")
|
||||||
|
|
||||||
|
|
||||||
func test_neighbouring_rows_have_different_backgrounds() -> void:
|
func test_neighbouring_rows_have_different_backgrounds() -> void:
|
||||||
var first: ListRow = auto_free(ListRow.create("Chrono Trigger", 0, 20))
|
var first: ListRow = auto_free(ListRow.create("Chrono Trigger", 0, 20))
|
||||||
var second: ListRow = auto_free(ListRow.create("Chrono Cross", 1, 20))
|
var second: ListRow = auto_free(ListRow.create("Chrono Cross", 1, 20))
|
||||||
var third: ListRow = auto_free(ListRow.create("Xenogears", 2, 20))
|
var third: ListRow = auto_free(ListRow.create("Xenogears", 2, 20))
|
||||||
|
|
||||||
assert_that(_background(first)).is_not_equal(_background(second))
|
assert_that(_background(first)).is_not_equal(_background(second))
|
||||||
assert_that(_background(first)).is_equal(_background(third))
|
assert_that(_background(first)).is_equal(_background(third))
|
||||||
|
|
||||||
|
|
||||||
func test_long_text_wraps() -> void:
|
func test_long_text_wraps() -> void:
|
||||||
var list_row: ListRow = auto_free(ListRow.create("Castlevania: Symphony of the Night", 0, 20))
|
var list_row: ListRow = auto_free(ListRow.create("Castlevania: Symphony of the Night", 0, 20))
|
||||||
|
|
||||||
assert_int(list_row.label.autowrap_mode).is_equal(TextServer.AUTOWRAP_WORD_SMART)
|
assert_int(list_row.label.autowrap_mode).is_equal(TextServer.AUTOWRAP_WORD_SMART)
|
||||||
@@ -7,62 +7,62 @@ var _hide_for_seconds: float
|
|||||||
|
|
||||||
|
|
||||||
func before_test() -> void:
|
func before_test() -> void:
|
||||||
_music_player = auto_free(MusicPlayer.new())
|
_music_player = auto_free(MusicPlayer.new())
|
||||||
_hide_beginning = Settings.hide_beginning
|
_hide_beginning = Settings.hide_beginning
|
||||||
_hide_length = Settings.hide_length
|
_hide_length = Settings.hide_length
|
||||||
_hide_for_seconds = Settings.hide_for_seconds
|
_hide_for_seconds = Settings.hide_for_seconds
|
||||||
Settings.hide_beginning = false
|
Settings.hide_beginning = false
|
||||||
Settings.hide_length = false
|
Settings.hide_length = false
|
||||||
Settings.hide_for_seconds = 5.0
|
Settings.hide_for_seconds = 5.0
|
||||||
|
|
||||||
|
|
||||||
func after_test() -> void:
|
func after_test() -> void:
|
||||||
Settings.hide_beginning = _hide_beginning
|
Settings.hide_beginning = _hide_beginning
|
||||||
Settings.hide_length = _hide_length
|
Settings.hide_length = _hide_length
|
||||||
Settings.hide_for_seconds = _hide_for_seconds
|
Settings.hide_for_seconds = _hide_for_seconds
|
||||||
|
|
||||||
|
|
||||||
func test_format_time() -> void:
|
func test_format_time() -> void:
|
||||||
assert_str(_music_player.format_time(0.0)).is_equal("00:00")
|
assert_str(_music_player.format_time(0.0)).is_equal("00:00")
|
||||||
assert_str(_music_player.format_time(65.0)).is_equal("01:05")
|
assert_str(_music_player.format_time(65.0)).is_equal("01:05")
|
||||||
assert_str(_music_player.format_time(3661.0)).is_equal("61:01")
|
assert_str(_music_player.format_time(3661.0)).is_equal("61:01")
|
||||||
|
|
||||||
|
|
||||||
func test_format_time_rounds_up_into_next_minute() -> void:
|
func test_format_time_rounds_up_into_next_minute() -> void:
|
||||||
assert_str(_music_player.format_time(59.6)).is_equal("01:00")
|
assert_str(_music_player.format_time(59.6)).is_equal("01:00")
|
||||||
|
|
||||||
|
|
||||||
func test_format_text_shows_position_and_length() -> void:
|
func test_format_text_shows_position_and_length() -> void:
|
||||||
assert_str(_music_player.format_text(10.0, 100.0)).is_equal("00:10 / 01:40")
|
assert_str(_music_player.format_text(10.0, 100.0)).is_equal("00:10 / 01:40")
|
||||||
|
|
||||||
|
|
||||||
func test_format_text_hides_length() -> void:
|
func test_format_text_hides_length() -> void:
|
||||||
Settings.hide_length = true
|
Settings.hide_length = true
|
||||||
|
|
||||||
assert_str(_music_player.format_text(10.0, 100.0)).is_equal("00:10 / ??:??")
|
assert_str(_music_player.format_text(10.0, 100.0)).is_equal("00:10 / ??:??")
|
||||||
|
|
||||||
|
|
||||||
func test_format_text_hides_position_at_start() -> void:
|
func test_format_text_hides_position_at_start() -> void:
|
||||||
Settings.hide_beginning = true
|
Settings.hide_beginning = true
|
||||||
|
|
||||||
assert_str(_music_player.format_text(3.0, 100.0)).is_equal("??:?? / 01:40")
|
assert_str(_music_player.format_text(3.0, 100.0)).is_equal("??:?? / 01:40")
|
||||||
|
|
||||||
|
|
||||||
func test_format_text_shows_position_after_hidden_start() -> void:
|
func test_format_text_shows_position_after_hidden_start() -> void:
|
||||||
Settings.hide_beginning = true
|
Settings.hide_beginning = true
|
||||||
|
|
||||||
assert_str(_music_player.format_text(5.0, 100.0)).is_equal("00:05 / 01:40")
|
assert_str(_music_player.format_text(5.0, 100.0)).is_equal("00:05 / 01:40")
|
||||||
|
|
||||||
|
|
||||||
func test_format_text_hides_everything_at_start() -> void:
|
func test_format_text_hides_everything_at_start() -> void:
|
||||||
Settings.hide_beginning = true
|
Settings.hide_beginning = true
|
||||||
Settings.hide_length = true
|
Settings.hide_length = true
|
||||||
|
|
||||||
assert_str(_music_player.format_text(3.0, 100.0)).is_equal("??:?? / ??:??")
|
assert_str(_music_player.format_text(3.0, 100.0)).is_equal("??:?? / ??:??")
|
||||||
|
|
||||||
|
|
||||||
func test_format_text_keeps_length_hidden_after_hidden_start() -> void:
|
func test_format_text_keeps_length_hidden_after_hidden_start() -> void:
|
||||||
Settings.hide_beginning = true
|
Settings.hide_beginning = true
|
||||||
Settings.hide_length = true
|
Settings.hide_length = true
|
||||||
|
|
||||||
assert_str(_music_player.format_text(5.0, 100.0)).is_equal("00:05 / ??:??")
|
assert_str(_music_player.format_text(5.0, 100.0)).is_equal("00:05 / ??:??")
|
||||||
@@ -4,143 +4,143 @@ var _server: FakeHttpTransport
|
|||||||
|
|
||||||
|
|
||||||
func before_test() -> void:
|
func before_test() -> void:
|
||||||
_server = FakeHttpTransport.new().install()
|
_server = FakeHttpTransport.new().install()
|
||||||
|
|
||||||
|
|
||||||
func after_test() -> void:
|
func after_test() -> void:
|
||||||
_server.uninstall()
|
_server.uninstall()
|
||||||
|
|
||||||
|
|
||||||
func test_fetch_song_list_passes_parsed_json() -> void:
|
func test_fetch_song_list_passes_parsed_json() -> void:
|
||||||
var songs: Array = [{"SongNo": 0, "Soundtrack": "Chrono Trigger", "Song": "Corridors of Time"}]
|
var songs: Array = [{"SongNo": 0, "Soundtrack": "Chrono Trigger", "Song": "Corridors of Time"}]
|
||||||
_server.respond_json("/music/list", songs)
|
_server.respond_json("/music/list", songs)
|
||||||
var received: Array = []
|
var received: Array = []
|
||||||
|
|
||||||
MusicServerClient.fetch_song_list(func(data: Array) -> void: received.append_array(data))
|
MusicServerClient.fetch_song_list(func(data: Array) -> void: received.append_array(data))
|
||||||
|
|
||||||
assert_int(received.size()).is_equal(1)
|
assert_int(received.size()).is_equal(1)
|
||||||
assert_int(int(received[0].SongNo)).is_equal(0)
|
assert_int(int(received[0].SongNo)).is_equal(0)
|
||||||
assert_str(received[0].Soundtrack).is_equal("Chrono Trigger")
|
assert_str(received[0].Soundtrack).is_equal("Chrono Trigger")
|
||||||
|
|
||||||
|
|
||||||
func test_fetch_random_song_uses_normal_endpoint() -> void:
|
func test_fetch_random_song_uses_normal_endpoint() -> void:
|
||||||
MusicServerClient.fetch_random_song(false, func(_body: PackedByteArray) -> void: pass)
|
MusicServerClient.fetch_random_song(false, func(_body: PackedByteArray) -> void: pass)
|
||||||
|
|
||||||
assert_array(_server.requested_paths).contains_exactly(["/music/rand"])
|
assert_array(_server.requested_paths).contains_exactly(["/music/rand"])
|
||||||
|
|
||||||
|
|
||||||
func test_fetch_random_song_uses_low_played_endpoint() -> void:
|
func test_fetch_random_song_uses_low_played_endpoint() -> void:
|
||||||
MusicServerClient.fetch_random_song(true, func(_body: PackedByteArray) -> void: pass)
|
MusicServerClient.fetch_random_song(true, func(_body: PackedByteArray) -> void: pass)
|
||||||
|
|
||||||
assert_array(_server.requested_paths).contains_exactly(["/music/rand/low"])
|
assert_array(_server.requested_paths).contains_exactly(["/music/rand/low"])
|
||||||
|
|
||||||
|
|
||||||
func test_fetch_song_passes_raw_bytes() -> void:
|
func test_fetch_song_passes_raw_bytes() -> void:
|
||||||
var mp3: PackedByteArray = PackedByteArray([0x49, 0x44, 0x33])
|
var mp3: PackedByteArray = PackedByteArray([0x49, 0x44, 0x33])
|
||||||
_server.respond_bytes("/music?song=4", mp3)
|
_server.respond_bytes("/music?song=4", mp3)
|
||||||
var received: Array[PackedByteArray] = []
|
var received: Array[PackedByteArray] = []
|
||||||
|
|
||||||
MusicServerClient.fetch_song(4, func(body: PackedByteArray) -> void: received.append(body))
|
MusicServerClient.fetch_song(4, func(body: PackedByteArray) -> void: received.append(body))
|
||||||
|
|
||||||
assert_array(received).contains_exactly([mp3])
|
assert_array(received).contains_exactly([mp3])
|
||||||
|
|
||||||
|
|
||||||
func test_failed_request_does_not_call_back() -> void:
|
func test_failed_request_does_not_call_back() -> void:
|
||||||
_server.respond_json("/music/list", [], 500)
|
_server.respond_json("/music/list", [], 500)
|
||||||
var called: Array[bool] = [false]
|
var called: Array[bool] = [false]
|
||||||
|
|
||||||
MusicServerClient.fetch_song_list(func(_data: Variant) -> void: called[0] = true)
|
MusicServerClient.fetch_song_list(func(_data: Variant) -> void: called[0] = true)
|
||||||
|
|
||||||
assert_bool(called[0]).is_false()
|
assert_bool(called[0]).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_invalid_json_does_not_call_back() -> void:
|
func test_invalid_json_does_not_call_back() -> void:
|
||||||
_server.respond_bytes("/music/info", "not json".to_utf8_buffer())
|
_server.respond_bytes("/music/info", "not json".to_utf8_buffer())
|
||||||
var called: Array[bool] = [false]
|
var called: Array[bool] = [false]
|
||||||
|
|
||||||
MusicServerClient.fetch_song_info(func(_data: Variant) -> void: called[0] = true)
|
MusicServerClient.fetch_song_info(func(_data: Variant) -> void: called[0] = true)
|
||||||
|
|
||||||
assert_bool(called[0]).is_false()
|
assert_bool(called[0]).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_failed_request_calls_on_failed() -> void:
|
func test_failed_request_calls_on_failed() -> void:
|
||||||
_server.respond_bytes("/music/rand", PackedByteArray(), 503)
|
_server.respond_bytes("/music/rand", PackedByteArray(), 503)
|
||||||
var outcome: Array[String] = []
|
var outcome: Array[String] = []
|
||||||
|
|
||||||
MusicServerClient.fetch_random_song(false,
|
MusicServerClient.fetch_random_song(false,
|
||||||
func(_body: PackedByteArray) -> void: outcome.append("done"),
|
func(_body: PackedByteArray) -> void: outcome.append("done"),
|
||||||
func() -> void: outcome.append("failed"))
|
func() -> void: outcome.append("failed"))
|
||||||
|
|
||||||
assert_array(outcome).contains_exactly(["failed"])
|
assert_array(outcome).contains_exactly(["failed"])
|
||||||
|
|
||||||
|
|
||||||
func test_invalid_json_calls_on_failed() -> void:
|
func test_invalid_json_calls_on_failed() -> void:
|
||||||
_server.respond_bytes("/music/info", "not json".to_utf8_buffer())
|
_server.respond_bytes("/music/info", "not json".to_utf8_buffer())
|
||||||
var outcome: Array[String] = []
|
var outcome: Array[String] = []
|
||||||
|
|
||||||
MusicServerClient.fetch_song_info(
|
MusicServerClient.fetch_song_info(
|
||||||
func(_data: Variant) -> void: outcome.append("done"),
|
func(_data: Variant) -> void: outcome.append("done"),
|
||||||
func() -> void: outcome.append("failed"))
|
func() -> void: outcome.append("failed"))
|
||||||
|
|
||||||
assert_array(outcome).contains_exactly(["failed"])
|
assert_array(outcome).contains_exactly(["failed"])
|
||||||
|
|
||||||
|
|
||||||
func test_successful_request_does_not_call_on_failed() -> void:
|
func test_successful_request_does_not_call_on_failed() -> void:
|
||||||
_server.respond_bytes("/music/addQue", PackedByteArray())
|
_server.respond_bytes("/music/addQue", PackedByteArray())
|
||||||
var outcome: Array[String] = []
|
var outcome: Array[String] = []
|
||||||
|
|
||||||
MusicServerClient.add_to_queue(
|
MusicServerClient.add_to_queue(
|
||||||
func() -> void: outcome.append("done"),
|
func() -> void: outcome.append("done"),
|
||||||
func() -> void: outcome.append("failed"))
|
func() -> void: outcome.append("failed"))
|
||||||
|
|
||||||
assert_array(outcome).contains_exactly(["done"])
|
assert_array(outcome).contains_exactly(["done"])
|
||||||
|
|
||||||
|
|
||||||
func test_send_calls_back_without_arguments() -> void:
|
func test_send_calls_back_without_arguments() -> void:
|
||||||
_server.respond_bytes("/music/reset", PackedByteArray())
|
_server.respond_bytes("/music/reset", PackedByteArray())
|
||||||
var called: Array[bool] = [false]
|
var called: Array[bool] = [false]
|
||||||
|
|
||||||
MusicServerClient.reset_playlist(func() -> void: called[0] = true)
|
MusicServerClient.reset_playlist(func() -> void: called[0] = true)
|
||||||
|
|
||||||
assert_bool(called[0]).is_true()
|
assert_bool(called[0]).is_true()
|
||||||
|
|
||||||
|
|
||||||
func test_mark_song_played_sends_put() -> void:
|
func test_mark_song_played_sends_put() -> void:
|
||||||
_server.respond_bytes("/music/played?song=3", PackedByteArray())
|
_server.respond_bytes("/music/played?song=3", PackedByteArray())
|
||||||
|
|
||||||
MusicServerClient.mark_song_played(3)
|
MusicServerClient.mark_song_played(3)
|
||||||
|
|
||||||
assert_array(_server.requested_paths).contains_exactly(["/music/played?song=3"])
|
assert_array(_server.requested_paths).contains_exactly(["/music/played?song=3"])
|
||||||
assert_array(_server.requested_methods).contains_exactly([HTTPClient.METHOD_PUT])
|
assert_array(_server.requested_methods).contains_exactly([HTTPClient.METHOD_PUT])
|
||||||
|
|
||||||
|
|
||||||
func test_character_name_is_url_encoded() -> void:
|
func test_character_name_is_url_encoded() -> void:
|
||||||
MusicServerClient.fetch_character_image("Paper Mario.png", func(_body: PackedByteArray) -> void: pass)
|
MusicServerClient.fetch_character_image("Paper Mario.png", func(_body: PackedByteArray) -> void: pass)
|
||||||
|
|
||||||
assert_array(_server.requested_paths).contains_exactly(["/character?name=Paper%20Mario.png"])
|
assert_array(_server.requested_paths).contains_exactly(["/character?name=Paper%20Mario.png"])
|
||||||
|
|
||||||
|
|
||||||
func test_requests_go_to_selected_server() -> void:
|
func test_requests_go_to_selected_server() -> void:
|
||||||
var previous_path: String = Settings.default_path
|
var previous_path: String = Settings.default_path
|
||||||
Settings.default_path = "http://localhost:8080"
|
Settings.default_path = "http://localhost:8080"
|
||||||
var requested_urls: Array[String] = []
|
var requested_urls: Array[String] = []
|
||||||
var recording_transport: HttpTransport = _RecordingTransport.new(requested_urls)
|
var recording_transport: HttpTransport = _RecordingTransport.new(requested_urls)
|
||||||
MusicServerClient.transport = recording_transport
|
MusicServerClient.transport = recording_transport
|
||||||
|
|
||||||
MusicServerClient.fetch_song_info(func(_data: Variant) -> void: pass)
|
MusicServerClient.fetch_song_info(func(_data: Variant) -> void: pass)
|
||||||
|
|
||||||
Settings.default_path = previous_path
|
Settings.default_path = previous_path
|
||||||
assert_array(requested_urls).contains_exactly(["http://localhost:8080/music/info"])
|
assert_array(requested_urls).contains_exactly(["http://localhost:8080/music/info"])
|
||||||
|
|
||||||
|
|
||||||
class _RecordingTransport:
|
class _RecordingTransport:
|
||||||
extends HttpTransport
|
extends HttpTransport
|
||||||
|
|
||||||
var _urls: Array[String]
|
var _urls: Array[String]
|
||||||
|
|
||||||
func _init(urls: Array[String]) -> void:
|
func _init(urls: Array[String]) -> void:
|
||||||
super(null)
|
super(null)
|
||||||
_urls = urls
|
_urls = urls
|
||||||
|
|
||||||
func request(url: String, _method: int, _on_complete: Callable) -> void:
|
func request(url: String, _method: int, _on_complete: Callable) -> void:
|
||||||
_urls.append(url)
|
_urls.append(url)
|
||||||
@@ -5,134 +5,134 @@ var _player: PlayerObject
|
|||||||
|
|
||||||
|
|
||||||
func before_test() -> void:
|
func before_test() -> void:
|
||||||
_winning_score = Settings.winning_score
|
_winning_score = Settings.winning_score
|
||||||
Settings.winning_score = 3
|
Settings.winning_score = 3
|
||||||
_player = PlayerObject.new("Crono")
|
_player = PlayerObject.new("Crono")
|
||||||
|
|
||||||
|
|
||||||
func after_test() -> void:
|
func after_test() -> void:
|
||||||
Settings.winning_score = _winning_score
|
Settings.winning_score = _winning_score
|
||||||
|
|
||||||
|
|
||||||
func test_first_point_triggers_first_point_signal() -> void:
|
func test_first_point_triggers_first_point_signal() -> void:
|
||||||
monitor_signals(_player, false)
|
monitor_signals(_player, false)
|
||||||
|
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
|
|
||||||
assert_int(_player.player_score).is_equal(1)
|
assert_int(_player.player_score).is_equal(1)
|
||||||
await assert_signal(_player).is_emitted("first_point_triggerd")
|
await assert_signal(_player).is_emitted("first_point_triggerd")
|
||||||
await assert_signal(_player).is_emitted("player_point_given")
|
await assert_signal(_player).is_emitted("player_point_given")
|
||||||
|
|
||||||
|
|
||||||
func test_one_point_from_winning_triggers_match_point() -> void:
|
func test_one_point_from_winning_triggers_match_point() -> void:
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
monitor_signals(_player, false)
|
monitor_signals(_player, false)
|
||||||
|
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
|
|
||||||
await assert_signal(_player).is_emitted("match_point_triggerd")
|
await assert_signal(_player).is_emitted("match_point_triggerd")
|
||||||
|
|
||||||
|
|
||||||
func test_reaching_winning_score_triggers_winner() -> void:
|
func test_reaching_winning_score_triggers_winner() -> void:
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
monitor_signals(_player, false)
|
monitor_signals(_player, false)
|
||||||
|
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
|
|
||||||
assert_int(_player.player_score).is_equal(3)
|
assert_int(_player.player_score).is_equal(3)
|
||||||
await assert_signal(_player).is_emitted("winner_triggerd")
|
await assert_signal(_player).is_emitted("winner_triggerd")
|
||||||
|
|
||||||
|
|
||||||
func test_score_does_not_go_past_winning_score() -> void:
|
func test_score_does_not_go_past_winning_score() -> void:
|
||||||
for i: int in 3:
|
for i: int in 3:
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
monitor_signals(_player, false)
|
monitor_signals(_player, false)
|
||||||
|
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
|
|
||||||
assert_int(_player.player_score).is_equal(3)
|
assert_int(_player.player_score).is_equal(3)
|
||||||
await assert_signal(_player).wait_until(50).is_not_emitted("player_point_given")
|
await assert_signal(_player).wait_until(50).is_not_emitted("player_point_given")
|
||||||
|
|
||||||
|
|
||||||
func test_ordinary_point_plays_point_sound() -> void:
|
func test_ordinary_point_plays_point_sound() -> void:
|
||||||
Settings.winning_score = 10
|
Settings.winning_score = 10
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
monitor_signals(_player, false)
|
monitor_signals(_player, false)
|
||||||
|
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
|
|
||||||
await assert_signal(_player).is_emitted("point_given_sound")
|
await assert_signal(_player).is_emitted("point_given_sound")
|
||||||
|
|
||||||
|
|
||||||
func test_minus_point_lowers_score() -> void:
|
func test_minus_point_lowers_score() -> void:
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
monitor_signals(_player, false)
|
monitor_signals(_player, false)
|
||||||
|
|
||||||
_player.minus_point()
|
_player.minus_point()
|
||||||
|
|
||||||
assert_int(_player.player_score).is_equal(0)
|
assert_int(_player.player_score).is_equal(0)
|
||||||
await assert_signal(_player).is_emitted("player_point_taken")
|
await assert_signal(_player).is_emitted("player_point_taken")
|
||||||
|
|
||||||
|
|
||||||
func test_score_does_not_go_below_zero() -> void:
|
func test_score_does_not_go_below_zero() -> void:
|
||||||
monitor_signals(_player, false)
|
monitor_signals(_player, false)
|
||||||
|
|
||||||
_player.minus_point()
|
_player.minus_point()
|
||||||
|
|
||||||
assert_int(_player.player_score).is_equal(0)
|
assert_int(_player.player_score).is_equal(0)
|
||||||
await assert_signal(_player).wait_until(50).is_not_emitted("player_point_taken")
|
await assert_signal(_player).wait_until(50).is_not_emitted("player_point_taken")
|
||||||
|
|
||||||
|
|
||||||
func test_dropping_back_to_zero_allows_first_point_again() -> void:
|
func test_dropping_back_to_zero_allows_first_point_again() -> void:
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
_player.minus_point()
|
_player.minus_point()
|
||||||
monitor_signals(_player, false)
|
monitor_signals(_player, false)
|
||||||
|
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
|
|
||||||
await assert_signal(_player).is_emitted("first_point_triggerd")
|
await assert_signal(_player).is_emitted("first_point_triggerd")
|
||||||
|
|
||||||
|
|
||||||
func test_reset_points() -> void:
|
func test_reset_points() -> void:
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
|
|
||||||
_player.reset_points()
|
_player.reset_points()
|
||||||
|
|
||||||
assert_int(_player.player_score).is_equal(0)
|
assert_int(_player.player_score).is_equal(0)
|
||||||
assert_bool(_player.is_first_point).is_true()
|
assert_bool(_player.is_first_point).is_true()
|
||||||
|
|
||||||
|
|
||||||
func test_id_is_a_uuid() -> void:
|
func test_id_is_a_uuid() -> void:
|
||||||
var uuid_pattern: RegEx = RegEx.create_from_string(
|
var uuid_pattern: RegEx = RegEx.create_from_string(
|
||||||
"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")
|
"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")
|
||||||
|
|
||||||
assert_object(uuid_pattern.search(_player.id)).is_not_null()
|
assert_object(uuid_pattern.search(_player.id)).is_not_null()
|
||||||
|
|
||||||
|
|
||||||
func test_every_player_gets_a_different_id() -> void:
|
func test_every_player_gets_a_different_id() -> void:
|
||||||
var ids: Dictionary = {}
|
var ids: Dictionary = {}
|
||||||
for i: int in 100:
|
for i: int in 100:
|
||||||
ids[PlayerObject.new("Player %d" % i).id] = true
|
ids[PlayerObject.new("Player %d" % i).id] = true
|
||||||
|
|
||||||
assert_int(ids.size()).is_equal(100)
|
assert_int(ids.size()).is_equal(100)
|
||||||
|
|
||||||
|
|
||||||
func test_winning_score_of_one_is_won_with_first_point() -> void:
|
func test_winning_score_of_one_is_won_with_first_point() -> void:
|
||||||
Settings.winning_score = 1
|
Settings.winning_score = 1
|
||||||
monitor_signals(_player, false)
|
monitor_signals(_player, false)
|
||||||
|
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
|
|
||||||
await assert_signal(_player).is_emitted("winner_triggerd")
|
await assert_signal(_player).is_emitted("winner_triggerd")
|
||||||
|
|
||||||
|
|
||||||
func test_first_point_is_match_point_when_winning_score_is_two() -> void:
|
func test_first_point_is_match_point_when_winning_score_is_two() -> void:
|
||||||
Settings.winning_score = 2
|
Settings.winning_score = 2
|
||||||
monitor_signals(_player, false)
|
monitor_signals(_player, false)
|
||||||
|
|
||||||
_player.add_point()
|
_player.add_point()
|
||||||
|
|
||||||
await assert_signal(_player).is_emitted("match_point_triggerd")
|
await assert_signal(_player).is_emitted("match_point_triggerd")
|
||||||
assert_bool(_player.is_first_point).is_false()
|
assert_bool(_player.is_first_point).is_false()
|
||||||
+98
-98
@@ -6,196 +6,196 @@ var _is_debug: bool
|
|||||||
|
|
||||||
|
|
||||||
func before_test() -> void:
|
func before_test() -> void:
|
||||||
_server = FakeHttpTransport.new().install()
|
_server = FakeHttpTransport.new().install()
|
||||||
_add_to_stats = Settings.add_to_stats
|
_add_to_stats = Settings.add_to_stats
|
||||||
_is_debug = Settings.is_debug
|
_is_debug = Settings.is_debug
|
||||||
Settings.add_to_stats = false
|
Settings.add_to_stats = false
|
||||||
Settings.is_debug = false
|
Settings.is_debug = false
|
||||||
Playlist.reset_playlist()
|
Playlist.reset_playlist()
|
||||||
Playlist.number_of_tracks_to_preload = 1
|
Playlist.number_of_tracks_to_preload = 1
|
||||||
|
|
||||||
|
|
||||||
func after_test() -> void:
|
func after_test() -> void:
|
||||||
Playlist.reset_playlist()
|
Playlist.reset_playlist()
|
||||||
Settings.add_to_stats = _add_to_stats
|
Settings.add_to_stats = _add_to_stats
|
||||||
Settings.is_debug = _is_debug
|
Settings.is_debug = _is_debug
|
||||||
_server.uninstall()
|
_server.uninstall()
|
||||||
|
|
||||||
|
|
||||||
func _add_songs(count: int) -> Array[SongObject]:
|
func _add_songs(count: int) -> Array[SongObject]:
|
||||||
var songs: Array[SongObject] = []
|
var songs: Array[SongObject] = []
|
||||||
for i: int in count:
|
for i: int in count:
|
||||||
var song: SongObject = SongObject.new()
|
var song: SongObject = SongObject.new()
|
||||||
song.song_number = i
|
song.song_number = i
|
||||||
song.soundtrack_title = "Soundtrack %d" % i
|
song.soundtrack_title = "Soundtrack %d" % i
|
||||||
song.song_title = "Song %d" % i
|
song.song_title = "Song %d" % i
|
||||||
Playlist.add_to_playlist(song)
|
Playlist.add_to_playlist(song)
|
||||||
songs.append(song)
|
songs.append(song)
|
||||||
return songs
|
return songs
|
||||||
|
|
||||||
|
|
||||||
func test_set_latest_played_song_advances() -> void:
|
func test_set_latest_played_song_advances() -> void:
|
||||||
_add_songs(3)
|
_add_songs(3)
|
||||||
|
|
||||||
Playlist.set_latest_played_song()
|
Playlist.set_latest_played_song()
|
||||||
|
|
||||||
assert_int(Playlist.latest_played_song).is_equal(1)
|
assert_int(Playlist.latest_played_song).is_equal(1)
|
||||||
|
|
||||||
|
|
||||||
func test_set_latest_played_song_stops_at_last_song() -> void:
|
func test_set_latest_played_song_stops_at_last_song() -> void:
|
||||||
_add_songs(2)
|
_add_songs(2)
|
||||||
|
|
||||||
Playlist.set_latest_played_song()
|
Playlist.set_latest_played_song()
|
||||||
Playlist.set_latest_played_song()
|
Playlist.set_latest_played_song()
|
||||||
Playlist.set_latest_played_song()
|
Playlist.set_latest_played_song()
|
||||||
|
|
||||||
assert_int(Playlist.latest_played_song).is_equal(1)
|
assert_int(Playlist.latest_played_song).is_equal(1)
|
||||||
|
|
||||||
|
|
||||||
func test_get_next_song_returns_latest_played() -> void:
|
func test_get_next_song_returns_latest_played() -> void:
|
||||||
var songs: Array[SongObject] = _add_songs(3)
|
var songs: Array[SongObject] = _add_songs(3)
|
||||||
Playlist.latest_played_song = 2
|
Playlist.latest_played_song = 2
|
||||||
|
|
||||||
assert_object(Playlist.get_next_song()).is_same(songs[2])
|
assert_object(Playlist.get_next_song()).is_same(songs[2])
|
||||||
|
|
||||||
|
|
||||||
func test_update_last_played_song_points_past_existing_songs() -> void:
|
func test_update_last_played_song_points_past_existing_songs() -> void:
|
||||||
_add_songs(4)
|
_add_songs(4)
|
||||||
|
|
||||||
Playlist.update_last_played_song()
|
Playlist.update_last_played_song()
|
||||||
|
|
||||||
assert_int(Playlist.latest_played_song).is_equal(4)
|
assert_int(Playlist.latest_played_song).is_equal(4)
|
||||||
|
|
||||||
|
|
||||||
func test_preloaded_songs_counts_unplayed_songs() -> void:
|
func test_preloaded_songs_counts_unplayed_songs() -> void:
|
||||||
var songs: Array[SongObject] = _add_songs(3)
|
var songs: Array[SongObject] = _add_songs(3)
|
||||||
songs[0].has_played = true
|
songs[0].has_played = true
|
||||||
|
|
||||||
assert_int(Playlist.get_preloaded_songs()).is_equal(2)
|
assert_int(Playlist.get_preloaded_songs()).is_equal(2)
|
||||||
|
|
||||||
|
|
||||||
func test_should_preload_more_songs_when_below_target() -> void:
|
func test_should_preload_more_songs_when_below_target() -> void:
|
||||||
var songs: Array[SongObject] = _add_songs(1)
|
var songs: Array[SongObject] = _add_songs(1)
|
||||||
songs[0].has_played = true
|
songs[0].has_played = true
|
||||||
|
|
||||||
assert_bool(Playlist.should_preload_more_songs()).is_true()
|
assert_bool(Playlist.should_preload_more_songs()).is_true()
|
||||||
|
|
||||||
|
|
||||||
func test_should_not_preload_more_songs_when_target_reached() -> void:
|
func test_should_not_preload_more_songs_when_target_reached() -> void:
|
||||||
_add_songs(1)
|
_add_songs(1)
|
||||||
|
|
||||||
assert_bool(Playlist.should_preload_more_songs()).is_false()
|
assert_bool(Playlist.should_preload_more_songs()).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_get_playlist_hides_unplayed_songs() -> void:
|
func test_get_playlist_hides_unplayed_songs() -> void:
|
||||||
var songs: Array[SongObject] = _add_songs(3)
|
var songs: Array[SongObject] = _add_songs(3)
|
||||||
songs[0].has_played = true
|
songs[0].has_played = true
|
||||||
|
|
||||||
assert_array(Playlist.get_playlist()).contains_exactly([songs[0]])
|
assert_array(Playlist.get_playlist()).contains_exactly([songs[0]])
|
||||||
|
|
||||||
|
|
||||||
func test_get_playlist_shows_everything_in_debug() -> void:
|
func test_get_playlist_shows_everything_in_debug() -> void:
|
||||||
Settings.is_debug = true
|
Settings.is_debug = true
|
||||||
var songs: Array[SongObject] = _add_songs(2)
|
var songs: Array[SongObject] = _add_songs(2)
|
||||||
|
|
||||||
assert_array(Playlist.get_playlist()).contains_exactly(songs)
|
assert_array(Playlist.get_playlist()).contains_exactly(songs)
|
||||||
|
|
||||||
|
|
||||||
func test_song_is_answered_marks_song() -> void:
|
func test_song_is_answered_marks_song() -> void:
|
||||||
var songs: Array[SongObject] = _add_songs(2)
|
var songs: Array[SongObject] = _add_songs(2)
|
||||||
|
|
||||||
Playlist.song_is_answered(1)
|
Playlist.song_is_answered(1)
|
||||||
|
|
||||||
assert_bool(songs[1].is_answered).is_true()
|
assert_bool(songs[1].is_answered).is_true()
|
||||||
assert_bool(songs[0].is_answered).is_false()
|
assert_bool(songs[0].is_answered).is_false()
|
||||||
|
|
||||||
|
|
||||||
func test_song_is_answered_reports_to_stats_when_enabled() -> void:
|
func test_song_is_answered_reports_to_stats_when_enabled() -> void:
|
||||||
Settings.add_to_stats = true
|
Settings.add_to_stats = true
|
||||||
_add_songs(2)
|
_add_songs(2)
|
||||||
|
|
||||||
Playlist.song_is_answered(1)
|
Playlist.song_is_answered(1)
|
||||||
|
|
||||||
assert_array(_server.requested_paths).contains_exactly(["/music/played?song=1"])
|
assert_array(_server.requested_paths).contains_exactly(["/music/played?song=1"])
|
||||||
|
|
||||||
|
|
||||||
func test_song_is_answered_does_not_report_when_stats_disabled() -> void:
|
func test_song_is_answered_does_not_report_when_stats_disabled() -> void:
|
||||||
_add_songs(2)
|
_add_songs(2)
|
||||||
|
|
||||||
Playlist.song_is_answered(1)
|
Playlist.song_is_answered(1)
|
||||||
|
|
||||||
assert_array(_server.requested_paths).is_empty()
|
assert_array(_server.requested_paths).is_empty()
|
||||||
|
|
||||||
|
|
||||||
func test_points_are_recorded_on_current_song() -> void:
|
func test_points_are_recorded_on_current_song() -> void:
|
||||||
var songs: Array[SongObject] = _add_songs(2)
|
var songs: Array[SongObject] = _add_songs(2)
|
||||||
Playlist.set_currently_playing_song(1)
|
Playlist.set_currently_playing_song(1)
|
||||||
|
|
||||||
Playlist.add_point("lucca-id")
|
Playlist.add_point("lucca-id")
|
||||||
Playlist.add_point("crono-id")
|
Playlist.add_point("crono-id")
|
||||||
|
|
||||||
assert_array(songs[1].players_given_point).contains_exactly(["lucca-id", "crono-id"])
|
assert_array(songs[1].players_given_point).contains_exactly(["lucca-id", "crono-id"])
|
||||||
assert_array(songs[0].players_given_point).is_empty()
|
assert_array(songs[0].players_given_point).is_empty()
|
||||||
|
|
||||||
|
|
||||||
func test_remove_point_from_current_song() -> void:
|
func test_remove_point_from_current_song() -> void:
|
||||||
var songs: Array[SongObject] = _add_songs(1)
|
var songs: Array[SongObject] = _add_songs(1)
|
||||||
Playlist.set_currently_playing_song(0)
|
Playlist.set_currently_playing_song(0)
|
||||||
Playlist.add_point("crono-id")
|
Playlist.add_point("crono-id")
|
||||||
Playlist.add_point("marle-id")
|
Playlist.add_point("marle-id")
|
||||||
|
|
||||||
Playlist.remove_point("crono-id")
|
Playlist.remove_point("crono-id")
|
||||||
|
|
||||||
assert_array(songs[0].players_given_point).contains_exactly(["marle-id"])
|
assert_array(songs[0].players_given_point).contains_exactly(["marle-id"])
|
||||||
|
|
||||||
|
|
||||||
func test_remove_player_removes_only_that_players_points() -> void:
|
func test_remove_player_removes_only_that_players_points() -> void:
|
||||||
var songs: Array[SongObject] = _add_songs(2)
|
var songs: Array[SongObject] = _add_songs(2)
|
||||||
songs[0].players_given_point.assign(["crono-id", "marle-id"])
|
songs[0].players_given_point.assign(["crono-id", "marle-id"])
|
||||||
songs[1].players_given_point.assign(["crono-id"])
|
songs[1].players_given_point.assign(["crono-id"])
|
||||||
|
|
||||||
Playlist.remove_player_from_list("marle-id")
|
Playlist.remove_player_from_list("marle-id")
|
||||||
|
|
||||||
assert_array(songs[0].players_given_point).contains_exactly(["crono-id"])
|
assert_array(songs[0].players_given_point).contains_exactly(["crono-id"])
|
||||||
assert_array(songs[1].players_given_point).contains_exactly(["crono-id"])
|
assert_array(songs[1].players_given_point).contains_exactly(["crono-id"])
|
||||||
|
|
||||||
|
|
||||||
func test_reset_playlist_clears_songs_and_position() -> void:
|
func test_reset_playlist_clears_songs_and_position() -> void:
|
||||||
_add_songs(3)
|
_add_songs(3)
|
||||||
Playlist.latest_played_song = 2
|
Playlist.latest_played_song = 2
|
||||||
Playlist.set_currently_playing_song(1)
|
Playlist.set_currently_playing_song(1)
|
||||||
|
|
||||||
Playlist.reset_playlist()
|
Playlist.reset_playlist()
|
||||||
|
|
||||||
assert_array(Playlist.song_object_array).is_empty()
|
assert_array(Playlist.song_object_array).is_empty()
|
||||||
assert_int(Playlist.latest_played_song).is_equal(0)
|
assert_int(Playlist.latest_played_song).is_equal(0)
|
||||||
assert_int(Playlist.currently_playing_song).is_equal(-1)
|
assert_int(Playlist.currently_playing_song).is_equal(-1)
|
||||||
|
|
||||||
|
|
||||||
func test_current_titles_are_hidden_until_answered() -> void:
|
func test_current_titles_are_hidden_until_answered() -> void:
|
||||||
var songs: Array[SongObject] = _add_songs(1)
|
var songs: Array[SongObject] = _add_songs(1)
|
||||||
Playlist.set_currently_playing_song(0)
|
Playlist.set_currently_playing_song(0)
|
||||||
|
|
||||||
assert_str(Playlist.get_current_soundtrack_title()).is_equal("????????")
|
assert_str(Playlist.get_current_soundtrack_title()).is_equal("????????")
|
||||||
|
|
||||||
songs[0].is_answered = true
|
songs[0].is_answered = true
|
||||||
|
|
||||||
assert_str(Playlist.get_current_soundtrack_title()).is_equal("Soundtrack 0")
|
assert_str(Playlist.get_current_soundtrack_title()).is_equal("Soundtrack 0")
|
||||||
assert_str(Playlist.get_current_song_title()).is_equal("Song 0")
|
assert_str(Playlist.get_current_song_title()).is_equal("Song 0")
|
||||||
|
|
||||||
|
|
||||||
func test_answering_when_nothing_is_playing_does_nothing() -> void:
|
func test_answering_when_nothing_is_playing_does_nothing() -> void:
|
||||||
Settings.add_to_stats = true
|
Settings.add_to_stats = true
|
||||||
var songs: Array[SongObject] = _add_songs(2)
|
var songs: Array[SongObject] = _add_songs(2)
|
||||||
|
|
||||||
Playlist.song_is_answered()
|
Playlist.song_is_answered()
|
||||||
|
|
||||||
assert_bool(songs[0].is_answered).is_false()
|
assert_bool(songs[0].is_answered).is_false()
|
||||||
assert_bool(songs[1].is_answered).is_false()
|
assert_bool(songs[1].is_answered).is_false()
|
||||||
assert_array(_server.requested_paths).is_empty()
|
assert_array(_server.requested_paths).is_empty()
|
||||||
|
|
||||||
|
|
||||||
func test_answering_with_empty_playlist_does_nothing() -> void:
|
func test_answering_with_empty_playlist_does_nothing() -> void:
|
||||||
Playlist.song_is_answered()
|
Playlist.song_is_answered()
|
||||||
|
|
||||||
assert_array(_server.requested_paths).is_empty()
|
assert_array(_server.requested_paths).is_empty()
|
||||||
+26
-26
@@ -6,57 +6,57 @@ var _search: Control
|
|||||||
|
|
||||||
|
|
||||||
func before_test() -> void:
|
func before_test() -> void:
|
||||||
_search = auto_free(SearchWindowScript.new())
|
_search = auto_free(SearchWindowScript.new())
|
||||||
_search.set_soundtracks([
|
_search.set_soundtracks([
|
||||||
"Chrono Trigger",
|
"Chrono Trigger",
|
||||||
"Final Fantasy VI",
|
"Final Fantasy VI",
|
||||||
"Mario & Luigi: Superstar Saga",
|
"Mario & Luigi: Superstar Saga",
|
||||||
"Pokémon Red",
|
"Pokémon Red",
|
||||||
"Q*bert",
|
"Q*bert",
|
||||||
"Super Mario 64",
|
"Super Mario 64",
|
||||||
"The Legend of Zelda: A Link to the Past",
|
"The Legend of Zelda: A Link to the Past",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
func test_plain_text_matches_case_insensitively() -> void:
|
func test_plain_text_matches_case_insensitively() -> void:
|
||||||
assert_array(_search.find_matches("chrono")).contains_exactly(["Chrono Trigger"])
|
assert_array(_search.find_matches("chrono")).contains_exactly(["Chrono Trigger"])
|
||||||
|
|
||||||
|
|
||||||
func test_contains_matches_come_before_letter_order_matches() -> void:
|
func test_contains_matches_come_before_letter_order_matches() -> void:
|
||||||
var matches: Array[String] = _search.find_matches("mario")
|
var matches: Array[String] = _search.find_matches("mario")
|
||||||
|
|
||||||
assert_array(matches).contains_exactly([
|
assert_array(matches).contains_exactly([
|
||||||
"Mario & Luigi: Superstar Saga",
|
"Mario & Luigi: Superstar Saga",
|
||||||
"Super Mario 64",
|
"Super Mario 64",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
func test_ignores_spaces() -> void:
|
func test_ignores_spaces() -> void:
|
||||||
assert_array(_search.find_matches("finalfantasy")).contains_exactly(["Final Fantasy VI"])
|
assert_array(_search.find_matches("finalfantasy")).contains_exactly(["Final Fantasy VI"])
|
||||||
|
|
||||||
|
|
||||||
func test_and_matches_ampersand() -> void:
|
func test_and_matches_ampersand() -> void:
|
||||||
assert_array(_search.find_matches("mario and luigi")).contains(["Mario & Luigi: Superstar Saga"])
|
assert_array(_search.find_matches("mario and luigi")).contains(["Mario & Luigi: Superstar Saga"])
|
||||||
|
|
||||||
|
|
||||||
func test_accented_letters_match_plain_letters() -> void:
|
func test_accented_letters_match_plain_letters() -> void:
|
||||||
assert_array(_search.find_matches("pokemon")).contains_exactly(["Pokémon Red"])
|
assert_array(_search.find_matches("pokemon")).contains_exactly(["Pokémon Red"])
|
||||||
|
|
||||||
|
|
||||||
func test_letters_in_order_match_abbreviations() -> void:
|
func test_letters_in_order_match_abbreviations() -> void:
|
||||||
assert_array(_search.find_matches("lozlttp")).contains_exactly([
|
assert_array(_search.find_matches("lozlttp")).contains_exactly([
|
||||||
"The Legend of Zelda: A Link to the Past",
|
"The Legend of Zelda: A Link to the Past",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
func test_regex_characters_are_matched_literally() -> void:
|
func test_regex_characters_are_matched_literally() -> void:
|
||||||
assert_array(_search.find_matches("q*b")).contains_exactly(["Q*bert"])
|
assert_array(_search.find_matches("q*b")).contains_exactly(["Q*bert"])
|
||||||
|
|
||||||
|
|
||||||
func test_no_matches() -> void:
|
func test_no_matches() -> void:
|
||||||
assert_array(_search.find_matches("metroid")).is_empty()
|
assert_array(_search.find_matches("metroid")).is_empty()
|
||||||
|
|
||||||
|
|
||||||
func test_clean_term() -> void:
|
func test_clean_term() -> void:
|
||||||
assert_str(_search.clean_term("Rock 'n Roll Racing")).is_equal("rockandrollracing")
|
assert_str(_search.clean_term("Rock 'n Roll Racing")).is_equal("rockandrollracing")
|
||||||
assert_str(_search.clean_term("Ys I & II")).is_equal("ysiandii")
|
assert_str(_search.clean_term("Ys I & II")).is_equal("ysiandii")
|
||||||
@@ -2,12 +2,12 @@ extends GdUnitTestSuite
|
|||||||
|
|
||||||
|
|
||||||
func test_version_comes_from_project_settings() -> void:
|
func test_version_comes_from_project_settings() -> void:
|
||||||
assert_str(Settings.version).is_equal(
|
assert_str(Settings.version).is_equal(
|
||||||
ProjectSettings.get_setting("application/config/version"))
|
ProjectSettings.get_setting("application/config/version"))
|
||||||
|
|
||||||
|
|
||||||
func test_version_is_major_minor_patch() -> void:
|
func test_version_is_major_minor_patch() -> void:
|
||||||
# The release job tags and names builds with this version
|
# The release job tags and names builds with this version
|
||||||
var pattern: RegEx = RegEx.create_from_string("^\\d+\\.\\d+\\.\\d+$")
|
var pattern: RegEx = RegEx.create_from_string("^\\d+\\.\\d+\\.\\d+$")
|
||||||
|
|
||||||
assert_object(pattern.search(Settings.version)).is_not_null()
|
assert_object(pattern.search(Settings.version)).is_not_null()
|
||||||
@@ -5,56 +5,56 @@ var _song: SongObject
|
|||||||
|
|
||||||
|
|
||||||
func before_test() -> void:
|
func before_test() -> void:
|
||||||
_is_debug = Settings.is_debug
|
_is_debug = Settings.is_debug
|
||||||
Settings.is_debug = false
|
Settings.is_debug = false
|
||||||
_song = SongObject.new()
|
_song = SongObject.new()
|
||||||
_song.song_number = 4
|
_song.song_number = 4
|
||||||
_song.soundtrack_title = "Final Fantasy VI"
|
_song.soundtrack_title = "Final Fantasy VI"
|
||||||
_song.song_title = "Dancing Mad"
|
_song.song_title = "Dancing Mad"
|
||||||
|
|
||||||
|
|
||||||
func after_test() -> void:
|
func after_test() -> void:
|
||||||
Settings.is_debug = _is_debug
|
Settings.is_debug = _is_debug
|
||||||
|
|
||||||
|
|
||||||
func test_titles_are_hidden_until_answered() -> void:
|
func test_titles_are_hidden_until_answered() -> void:
|
||||||
assert_str(_song.get_soundtrack_title()).is_equal("????????")
|
assert_str(_song.get_soundtrack_title()).is_equal("????????")
|
||||||
assert_str(_song.get_song_title()).is_equal("??????")
|
assert_str(_song.get_song_title()).is_equal("??????")
|
||||||
assert_str(_song.get_song_info()).is_equal("??? - ???")
|
assert_str(_song.get_song_info()).is_equal("??? - ???")
|
||||||
|
|
||||||
|
|
||||||
func test_titles_are_shown_once_answered() -> void:
|
func test_titles_are_shown_once_answered() -> void:
|
||||||
_song.is_answered = true
|
_song.is_answered = true
|
||||||
|
|
||||||
assert_str(_song.get_soundtrack_title()).is_equal("Final Fantasy VI")
|
assert_str(_song.get_soundtrack_title()).is_equal("Final Fantasy VI")
|
||||||
assert_str(_song.get_song_title()).is_equal("Dancing Mad")
|
assert_str(_song.get_song_title()).is_equal("Dancing Mad")
|
||||||
assert_str(_song.get_song_info()).is_equal("5. Final Fantasy VI - Dancing Mad")
|
assert_str(_song.get_song_info()).is_equal("5. Final Fantasy VI - Dancing Mad")
|
||||||
|
|
||||||
|
|
||||||
func test_debug_info_shows_unanswered_songs() -> void:
|
func test_debug_info_shows_unanswered_songs() -> void:
|
||||||
Settings.is_debug = true
|
Settings.is_debug = true
|
||||||
|
|
||||||
assert_str(_song.get_song_info()).is_equal(
|
assert_str(_song.get_song_info()).is_equal(
|
||||||
"5. Final Fantasy VI - Dancing Mad | played: false | answered: false")
|
"5. Final Fantasy VI - Dancing Mad | played: false | answered: false")
|
||||||
|
|
||||||
|
|
||||||
func test_points_are_kept_in_the_order_given() -> void:
|
func test_points_are_kept_in_the_order_given() -> void:
|
||||||
_song.add_point("marle-id")
|
_song.add_point("marle-id")
|
||||||
_song.add_point("crono-id")
|
_song.add_point("crono-id")
|
||||||
|
|
||||||
assert_array(_song.players_given_point).contains_exactly(["marle-id", "crono-id"])
|
assert_array(_song.players_given_point).contains_exactly(["marle-id", "crono-id"])
|
||||||
|
|
||||||
|
|
||||||
func test_player_gets_at_most_one_point_per_song() -> void:
|
func test_player_gets_at_most_one_point_per_song() -> void:
|
||||||
_song.add_point("crono-id")
|
_song.add_point("crono-id")
|
||||||
_song.add_point("crono-id")
|
_song.add_point("crono-id")
|
||||||
|
|
||||||
assert_array(_song.players_given_point).contains_exactly(["crono-id"])
|
assert_array(_song.players_given_point).contains_exactly(["crono-id"])
|
||||||
|
|
||||||
|
|
||||||
func test_removing_point_of_player_without_point_changes_nothing() -> void:
|
func test_removing_point_of_player_without_point_changes_nothing() -> void:
|
||||||
_song.add_point("crono-id")
|
_song.add_point("crono-id")
|
||||||
|
|
||||||
_song.remove_point("marle-id")
|
_song.remove_point("marle-id")
|
||||||
|
|
||||||
assert_array(_song.players_given_point).contains_exactly(["crono-id"])
|
assert_array(_song.players_given_point).contains_exactly(["crono-id"])
|
||||||
+32
-32
@@ -12,42 +12,42 @@ const SIZE: Vector2i = Vector2i(1920, 1080)
|
|||||||
|
|
||||||
|
|
||||||
func _initialize() -> void:
|
func _initialize() -> void:
|
||||||
_take.call_deferred()
|
_take.call_deferred()
|
||||||
|
|
||||||
|
|
||||||
func _take() -> void:
|
func _take() -> void:
|
||||||
var args: PackedStringArray = OS.get_cmdline_user_args()
|
var args: PackedStringArray = OS.get_cmdline_user_args()
|
||||||
var out_dir: String = args[0] if !args.is_empty() else "user://screenshots"
|
var out_dir: String = args[0] if !args.is_empty() else "user://screenshots"
|
||||||
DirAccess.make_dir_recursive_absolute(out_dir)
|
DirAccess.make_dir_recursive_absolute(out_dir)
|
||||||
var draws: bool = DisplayServer.get_name() != "headless"
|
var draws: bool = DisplayServer.get_name() != "headless"
|
||||||
|
|
||||||
# Loaded here, not named as a class: autoloads such as Playlist do not exist yet
|
# Loaded here, not named as a class: autoloads such as Playlist do not exist yet
|
||||||
# when this script is compiled
|
# when this script is compiled
|
||||||
var ui_tour: GDScript = load("res://tests/fakes/ui_tour.gd")
|
var ui_tour: GDScript = load("res://tests/fakes/ui_tour.gd")
|
||||||
ui_tour.prepare_autoloads()
|
ui_tour.prepare_autoloads()
|
||||||
var server: RefCounted = ui_tour.make_server().install()
|
var server: RefCounted = ui_tour.make_server().install()
|
||||||
|
|
||||||
# Drawn at the layout size, so the pictures do not depend on the screen size
|
# Drawn at the layout size, so the pictures do not depend on the screen size
|
||||||
var viewport: SubViewport = SubViewport.new()
|
var viewport: SubViewport = SubViewport.new()
|
||||||
viewport.size = SIZE
|
viewport.size = SIZE
|
||||||
viewport.gui_embed_subwindows = true
|
viewport.gui_embed_subwindows = true
|
||||||
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
||||||
root.add_child(viewport)
|
root.add_child(viewport)
|
||||||
var main: Control = load("res://MainWindow.tscn").instantiate()
|
var main: Control = load("res://MainWindow.tscn").instantiate()
|
||||||
viewport.add_child(main)
|
viewport.add_child(main)
|
||||||
|
|
||||||
var layout: Dictionary = {}
|
var layout: Dictionary = {}
|
||||||
var save_state: Callable = func(state: String, popup: Node) -> void:
|
var save_state: Callable = func(state: String, popup: Node) -> void:
|
||||||
layout[state] = ui_tour.dump_layout(main, main if popup == null else popup)
|
layout[state] = ui_tour.dump_layout(main, main if popup == null else popup)
|
||||||
if draws:
|
if draws:
|
||||||
await RenderingServer.frame_post_draw
|
await RenderingServer.frame_post_draw
|
||||||
viewport.get_texture().get_image().save_png(out_dir.path_join(state + ".png"))
|
viewport.get_texture().get_image().save_png(out_dir.path_join(state + ".png"))
|
||||||
print("Saved state ", state)
|
print("Saved state ", state)
|
||||||
await ui_tour.new(main).run(save_state)
|
await ui_tour.new(main).run(save_state)
|
||||||
|
|
||||||
var file: FileAccess = FileAccess.open(out_dir.path_join("layout.json"), FileAccess.WRITE)
|
var file: FileAccess = FileAccess.open(out_dir.path_join("layout.json"), FileAccess.WRITE)
|
||||||
file.store_string(JSON.stringify(layout, " ", true))
|
file.store_string(JSON.stringify(layout, " ", true))
|
||||||
file.close()
|
file.close()
|
||||||
server.uninstall()
|
server.uninstall()
|
||||||
main.queue_free()
|
main.queue_free()
|
||||||
quit()
|
quit()
|
||||||
+6
-6
@@ -14,9 +14,9 @@ signal qr_pressed
|
|||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
$SearchButton.pressed.connect(search_pressed.emit)
|
$SearchButton.pressed.connect(search_pressed.emit)
|
||||||
sync_button.pressed.connect(sync_pressed.emit)
|
sync_button.pressed.connect(sync_pressed.emit)
|
||||||
$StatisticsButton.pressed.connect(statistics_pressed.emit)
|
$StatisticsButton.pressed.connect(statistics_pressed.emit)
|
||||||
$ShortcutsButton.pressed.connect(shortcuts_pressed.emit)
|
$ShortcutsButton.pressed.connect(shortcuts_pressed.emit)
|
||||||
$AboutButton.pressed.connect(about_pressed.emit)
|
$AboutButton.pressed.connect(about_pressed.emit)
|
||||||
$QRButton.pressed.connect(qr_pressed.emit)
|
$QRButton.pressed.connect(qr_pressed.emit)
|
||||||
Reference in new issue
Block a user