gemba 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/THIRD_PARTY_NOTICES +37 -2
- data/assets/placeholder_boxart.png +0 -0
- data/bin/gemba +2 -2
- data/ext/gemba/extconf.rb +23 -1
- data/ext/gemba/gemba_ext.c +436 -2
- data/ext/gemba/gemba_ext.h +2 -0
- data/gemba.gemspec +5 -3
- data/lib/gemba/achievements/achievement.rb +23 -0
- data/lib/gemba/achievements/backend.rb +186 -0
- data/lib/gemba/achievements/cache.rb +70 -0
- data/lib/gemba/achievements/credentials_presenter.rb +142 -0
- data/lib/gemba/achievements/fake_backend.rb +205 -0
- data/lib/gemba/achievements/null_backend.rb +11 -0
- data/lib/gemba/achievements/offline_backend.rb +168 -0
- data/lib/gemba/achievements/retro_achievements/backend.rb +453 -0
- data/lib/gemba/achievements/retro_achievements/cli_sync_requester.rb +64 -0
- data/lib/gemba/achievements/retro_achievements/ping_worker.rb +27 -0
- data/lib/gemba/achievements.rb +19 -0
- data/lib/gemba/achievements_window.rb +556 -0
- data/lib/gemba/app_controller.rb +1015 -0
- data/lib/gemba/bios.rb +54 -0
- data/lib/gemba/boxart_fetcher/libretro_backend.rb +39 -0
- data/lib/gemba/boxart_fetcher/null_backend.rb +12 -0
- data/lib/gemba/boxart_fetcher.rb +79 -0
- data/lib/gemba/bus_emitter.rb +13 -0
- data/lib/gemba/child_window.rb +24 -1
- data/lib/gemba/cli/commands/config_cmd.rb +83 -0
- data/lib/gemba/cli/commands/decode.rb +154 -0
- data/lib/gemba/cli/commands/patch.rb +78 -0
- data/lib/gemba/cli/commands/play.rb +78 -0
- data/lib/gemba/cli/commands/record.rb +114 -0
- data/lib/gemba/cli/commands/replay.rb +161 -0
- data/lib/gemba/cli/commands/retro_achievements.rb +213 -0
- data/lib/gemba/cli/commands/version.rb +22 -0
- data/lib/gemba/cli.rb +52 -364
- data/lib/gemba/config.rb +134 -1
- data/lib/gemba/data/gb_games.json +1 -0
- data/lib/gemba/data/gb_md5.json +1 -0
- data/lib/gemba/data/gba_games.json +1 -0
- data/lib/gemba/data/gba_md5.json +1 -0
- data/lib/gemba/data/gbc_games.json +1 -0
- data/lib/gemba/data/gbc_md5.json +1 -0
- data/lib/gemba/emulator_frame.rb +1060 -0
- data/lib/gemba/event_bus.rb +48 -0
- data/lib/gemba/frame_stack.rb +60 -0
- data/lib/gemba/game_index.rb +84 -0
- data/lib/gemba/game_picker_frame.rb +268 -0
- data/lib/gemba/gamepad_map.rb +103 -0
- data/lib/gemba/headless.rb +6 -5
- data/lib/gemba/headless_player.rb +33 -3
- data/lib/gemba/help_window.rb +61 -0
- data/lib/gemba/hotkey_map.rb +3 -1
- data/lib/gemba/input_recorder.rb +107 -0
- data/lib/gemba/input_replayer.rb +119 -0
- data/lib/gemba/keyboard_map.rb +90 -0
- data/lib/gemba/locales/en.yml +97 -5
- data/lib/gemba/locales/ja.yml +97 -5
- data/lib/gemba/main_window.rb +56 -0
- data/lib/gemba/modal_stack.rb +81 -0
- data/lib/gemba/patcher_window.rb +223 -0
- data/lib/gemba/platform/gb.rb +21 -0
- data/lib/gemba/platform/gba.rb +21 -0
- data/lib/gemba/platform/gbc.rb +23 -0
- data/lib/gemba/platform.rb +20 -0
- data/lib/gemba/platform_open.rb +19 -0
- data/lib/gemba/recorder.rb +4 -3
- data/lib/gemba/replay_player.rb +691 -0
- data/lib/gemba/rom_info.rb +57 -0
- data/lib/gemba/rom_info_window.rb +16 -3
- data/lib/gemba/rom_library.rb +106 -0
- data/lib/gemba/rom_overrides.rb +47 -0
- data/lib/gemba/rom_patcher/bps.rb +161 -0
- data/lib/gemba/rom_patcher/ips.rb +101 -0
- data/lib/gemba/rom_patcher/ups.rb +118 -0
- data/lib/gemba/rom_patcher.rb +109 -0
- data/lib/gemba/{rom_loader.rb → rom_resolver.rb} +7 -6
- data/lib/gemba/runtime.rb +59 -26
- data/lib/gemba/save_state_manager.rb +4 -7
- data/lib/gemba/save_state_picker.rb +17 -4
- data/lib/gemba/session_logger.rb +64 -0
- data/lib/gemba/settings/audio_tab.rb +77 -0
- data/lib/gemba/settings/gamepad_tab.rb +351 -0
- data/lib/gemba/settings/hotkeys_tab.rb +259 -0
- data/lib/gemba/settings/paths.rb +11 -0
- data/lib/gemba/settings/recording_tab.rb +83 -0
- data/lib/gemba/settings/save_states_tab.rb +91 -0
- data/lib/gemba/settings/system_tab.rb +362 -0
- data/lib/gemba/settings/video_tab.rb +318 -0
- data/lib/gemba/settings_window.rb +162 -1036
- data/lib/gemba/version.rb +1 -1
- data/lib/gemba/virtual_keyboard.rb +19 -0
- data/lib/gemba.rb +2 -12
- data/test/achievements_window/test_bulk_sync.rb +218 -0
- data/test/achievements_window/test_bus_events.rb +125 -0
- data/test/achievements_window/test_close_confirmation.rb +201 -0
- data/test/achievements_window/test_initial_state.rb +164 -0
- data/test/achievements_window/test_sorting.rb +227 -0
- data/test/achievements_window/test_tree_rendering.rb +133 -0
- data/test/fixtures/fake_bios.bin +0 -0
- data/test/fixtures/pong.gba +0 -0
- data/test/fixtures/test.gb +0 -0
- data/test/fixtures/test.gbc +0 -0
- data/test/fixtures/test_quicksave.ss +0 -0
- data/test/screenshots/no_focus.png +0 -0
- data/test/shared/teek_test_worker.rb +17 -1
- data/test/shared/tk_test_helper.rb +91 -4
- data/test/support/achievements_window_helpers.rb +18 -0
- data/test/support/fake_core.rb +25 -0
- data/test/support/fake_ra_runtime.rb +74 -0
- data/test/support/fake_requester.rb +68 -0
- data/test/support/player_helpers.rb +20 -5
- data/test/test_achievement.rb +32 -0
- data/test/{test_player.rb → test_app_controller.rb} +353 -85
- data/test/test_bios.rb +123 -0
- data/test/test_boxart_fetcher.rb +150 -0
- data/test/test_cli.rb +17 -265
- data/test/test_cli_config.rb +64 -0
- data/test/test_cli_decode.rb +97 -0
- data/test/test_cli_patch.rb +58 -0
- data/test/test_cli_play.rb +213 -0
- data/test/test_cli_ra.rb +175 -0
- data/test/test_cli_record.rb +69 -0
- data/test/test_cli_replay.rb +72 -0
- data/test/test_cli_sync_requester.rb +152 -0
- data/test/test_cli_version.rb +27 -0
- data/test/test_config.rb +2 -3
- data/test/test_config_ra.rb +69 -0
- data/test/test_core.rb +62 -1
- data/test/test_credentials_presenter.rb +192 -0
- data/test/test_event_bus.rb +100 -0
- data/test/test_fake_backend_achievements.rb +130 -0
- data/test/test_fake_backend_auth.rb +68 -0
- data/test/test_game_index.rb +77 -0
- data/test/test_game_picker_frame.rb +310 -0
- data/test/test_gamepad_map.rb +1 -3
- data/test/test_headless_player.rb +17 -3
- data/test/test_help_window.rb +82 -0
- data/test/test_hotkey_map.rb +22 -1
- data/test/test_input_recorder.rb +179 -0
- data/test/test_input_replay_determinism.rb +113 -0
- data/test/test_input_replayer.rb +162 -0
- data/test/test_keyboard_map.rb +1 -3
- data/test/test_libretro_backend.rb +41 -0
- data/test/test_locale.rb +1 -1
- data/test/test_logging.rb +123 -0
- data/test/test_null_backend.rb +42 -0
- data/test/test_offline_backend.rb +116 -0
- data/test/test_overlay_renderer.rb +1 -1
- data/test/test_platform.rb +149 -0
- data/test/test_ra_backend.rb +313 -0
- data/test/test_ra_backend_unlock_gate.rb +56 -0
- data/test/test_recorder.rb +0 -3
- data/test/test_replay_player.rb +316 -0
- data/test/test_rom_info.rb +149 -0
- data/test/test_rom_overrides.rb +86 -0
- data/test/test_rom_patcher.rb +382 -0
- data/test/{test_rom_loader.rb → test_rom_resolver.rb} +25 -26
- data/test/test_save_state_manager.rb +2 -4
- data/test/test_settings_audio.rb +107 -0
- data/test/test_settings_hotkeys.rb +83 -66
- data/test/test_settings_recording.rb +49 -0
- data/test/test_settings_save_states.rb +97 -0
- data/test/test_settings_system.rb +133 -0
- data/test/test_settings_video.rb +450 -0
- data/test/test_settings_window.rb +76 -507
- data/test/test_tip_service.rb +6 -6
- data/test/test_toast_overlay.rb +1 -1
- data/test/test_virtual_events.rb +156 -0
- data/test/test_virtual_keyboard.rb +1 -1
- data/vendor/rcheevos/CHANGELOG.md +495 -0
- data/vendor/rcheevos/LICENSE +21 -0
- data/vendor/rcheevos/Package.swift +33 -0
- data/vendor/rcheevos/README.md +67 -0
- data/vendor/rcheevos/include/module.modulemap +70 -0
- data/vendor/rcheevos/include/rc_api_editor.h +296 -0
- data/vendor/rcheevos/include/rc_api_info.h +280 -0
- data/vendor/rcheevos/include/rc_api_request.h +77 -0
- data/vendor/rcheevos/include/rc_api_runtime.h +417 -0
- data/vendor/rcheevos/include/rc_api_user.h +262 -0
- data/vendor/rcheevos/include/rc_client.h +877 -0
- data/vendor/rcheevos/include/rc_client_raintegration.h +101 -0
- data/vendor/rcheevos/include/rc_consoles.h +138 -0
- data/vendor/rcheevos/include/rc_error.h +59 -0
- data/vendor/rcheevos/include/rc_export.h +100 -0
- data/vendor/rcheevos/include/rc_hash.h +200 -0
- data/vendor/rcheevos/include/rc_runtime.h +148 -0
- data/vendor/rcheevos/include/rc_runtime_types.h +452 -0
- data/vendor/rcheevos/include/rc_util.h +51 -0
- data/vendor/rcheevos/include/rcheevos.h +8 -0
- data/vendor/rcheevos/src/rapi/rc_api_common.c +1379 -0
- data/vendor/rcheevos/src/rapi/rc_api_common.h +88 -0
- data/vendor/rcheevos/src/rapi/rc_api_editor.c +625 -0
- data/vendor/rcheevos/src/rapi/rc_api_info.c +587 -0
- data/vendor/rcheevos/src/rapi/rc_api_runtime.c +901 -0
- data/vendor/rcheevos/src/rapi/rc_api_user.c +483 -0
- data/vendor/rcheevos/src/rc_client.c +6941 -0
- data/vendor/rcheevos/src/rc_client_external.c +281 -0
- data/vendor/rcheevos/src/rc_client_external.h +177 -0
- data/vendor/rcheevos/src/rc_client_external_versions.h +171 -0
- data/vendor/rcheevos/src/rc_client_internal.h +409 -0
- data/vendor/rcheevos/src/rc_client_raintegration.c +566 -0
- data/vendor/rcheevos/src/rc_client_raintegration_internal.h +61 -0
- data/vendor/rcheevos/src/rc_client_types.natvis +396 -0
- data/vendor/rcheevos/src/rc_compat.c +251 -0
- data/vendor/rcheevos/src/rc_compat.h +121 -0
- data/vendor/rcheevos/src/rc_libretro.c +915 -0
- data/vendor/rcheevos/src/rc_libretro.h +98 -0
- data/vendor/rcheevos/src/rc_util.c +199 -0
- data/vendor/rcheevos/src/rc_version.c +11 -0
- data/vendor/rcheevos/src/rc_version.h +32 -0
- data/vendor/rcheevos/src/rcheevos/alloc.c +312 -0
- data/vendor/rcheevos/src/rcheevos/condition.c +754 -0
- data/vendor/rcheevos/src/rcheevos/condset.c +777 -0
- data/vendor/rcheevos/src/rcheevos/consoleinfo.c +1215 -0
- data/vendor/rcheevos/src/rcheevos/format.c +330 -0
- data/vendor/rcheevos/src/rcheevos/lboard.c +287 -0
- data/vendor/rcheevos/src/rcheevos/memref.c +805 -0
- data/vendor/rcheevos/src/rcheevos/operand.c +607 -0
- data/vendor/rcheevos/src/rcheevos/rc_internal.h +390 -0
- data/vendor/rcheevos/src/rcheevos/rc_runtime_types.natvis +541 -0
- data/vendor/rcheevos/src/rcheevos/rc_validate.c +1406 -0
- data/vendor/rcheevos/src/rcheevos/rc_validate.h +18 -0
- data/vendor/rcheevos/src/rcheevos/richpresence.c +922 -0
- data/vendor/rcheevos/src/rcheevos/runtime.c +852 -0
- data/vendor/rcheevos/src/rcheevos/runtime_progress.c +1073 -0
- data/vendor/rcheevos/src/rcheevos/trigger.c +344 -0
- data/vendor/rcheevos/src/rcheevos/value.c +935 -0
- data/vendor/rcheevos/src/rhash/aes.c +480 -0
- data/vendor/rcheevos/src/rhash/aes.h +49 -0
- data/vendor/rcheevos/src/rhash/cdreader.c +838 -0
- data/vendor/rcheevos/src/rhash/hash.c +1402 -0
- data/vendor/rcheevos/src/rhash/hash_disc.c +1340 -0
- data/vendor/rcheevos/src/rhash/hash_encrypted.c +566 -0
- data/vendor/rcheevos/src/rhash/hash_rom.c +426 -0
- data/vendor/rcheevos/src/rhash/hash_zip.c +460 -0
- data/vendor/rcheevos/src/rhash/md5.c +382 -0
- data/vendor/rcheevos/src/rhash/md5.h +91 -0
- data/vendor/rcheevos/src/rhash/rc_hash_internal.h +116 -0
- data/vendor/rcheevos/test/libretro.h +205 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_common.c +941 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_editor.c +931 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_info.c +545 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_runtime.c +2213 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_user.c +998 -0
- data/vendor/rcheevos/test/rcheevos/mock_memory.h +32 -0
- data/vendor/rcheevos/test/rcheevos/test_condition.c +570 -0
- data/vendor/rcheevos/test/rcheevos/test_condset.c +5170 -0
- data/vendor/rcheevos/test/rcheevos/test_consoleinfo.c +203 -0
- data/vendor/rcheevos/test/rcheevos/test_format.c +112 -0
- data/vendor/rcheevos/test/rcheevos/test_lboard.c +746 -0
- data/vendor/rcheevos/test/rcheevos/test_memref.c +520 -0
- data/vendor/rcheevos/test/rcheevos/test_operand.c +692 -0
- data/vendor/rcheevos/test/rcheevos/test_rc_validate.c +502 -0
- data/vendor/rcheevos/test/rcheevos/test_richpresence.c +1564 -0
- data/vendor/rcheevos/test/rcheevos/test_runtime.c +1667 -0
- data/vendor/rcheevos/test/rcheevos/test_runtime_progress.c +1821 -0
- data/vendor/rcheevos/test/rcheevos/test_timing.c +166 -0
- data/vendor/rcheevos/test/rcheevos/test_trigger.c +2521 -0
- data/vendor/rcheevos/test/rcheevos/test_value.c +870 -0
- data/vendor/rcheevos/test/rcheevos-test.sln +46 -0
- data/vendor/rcheevos/test/rcheevos-test.vcxproj +239 -0
- data/vendor/rcheevos/test/rcheevos-test.vcxproj.filters +335 -0
- data/vendor/rcheevos/test/rhash/data.c +657 -0
- data/vendor/rcheevos/test/rhash/data.h +32 -0
- data/vendor/rcheevos/test/rhash/mock_filereader.c +236 -0
- data/vendor/rcheevos/test/rhash/mock_filereader.h +31 -0
- data/vendor/rcheevos/test/rhash/test_cdreader.c +920 -0
- data/vendor/rcheevos/test/rhash/test_hash.c +310 -0
- data/vendor/rcheevos/test/rhash/test_hash_disc.c +1450 -0
- data/vendor/rcheevos/test/rhash/test_hash_rom.c +899 -0
- data/vendor/rcheevos/test/rhash/test_hash_zip.c +551 -0
- data/vendor/rcheevos/test/test.c +113 -0
- data/vendor/rcheevos/test/test_framework.h +205 -0
- data/vendor/rcheevos/test/test_rc_client.c +10509 -0
- data/vendor/rcheevos/test/test_rc_client_external.c +2197 -0
- data/vendor/rcheevos/test/test_rc_client_raintegration.c +441 -0
- data/vendor/rcheevos/test/test_rc_libretro.c +952 -0
- data/vendor/rcheevos/test/test_types.natvis +9 -0
- data/vendor/rcheevos/validator/validator.c +658 -0
- data/vendor/rcheevos/validator/validator.vcxproj +152 -0
- data/vendor/rcheevos/validator/validator.vcxproj.filters +82 -0
- metadata +274 -11
- data/lib/gemba/input_mappings.rb +0 -214
- data/lib/gemba/player.rb +0 -1525
data/lib/gemba/version.rb
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'set'
|
|
4
|
+
|
|
5
|
+
module Gemba
|
|
6
|
+
# Virtual keyboard device that tracks key press/release state.
|
|
7
|
+
# Presents the same interface as an SDL gamepad: +button?+ and +closed?+.
|
|
8
|
+
class VirtualKeyboard
|
|
9
|
+
def initialize
|
|
10
|
+
@held = Set.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def press(keysym) = @held.add(keysym)
|
|
14
|
+
def release(keysym) = @held.delete(keysym)
|
|
15
|
+
def button?(keysym) = @held.include?(keysym)
|
|
16
|
+
def closed? = false
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
data/lib/gemba.rb
CHANGED
|
@@ -1,17 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "gemba/version"
|
|
3
4
|
require "teek"
|
|
4
5
|
require "teek/sdl2"
|
|
5
6
|
require_relative "gemba/runtime"
|
|
6
|
-
require_relative "gemba/
|
|
7
|
-
require_relative "gemba/tip_service"
|
|
8
|
-
require_relative "gemba/settings_window"
|
|
9
|
-
require_relative "gemba/rom_info_window"
|
|
10
|
-
require_relative "gemba/save_state_picker"
|
|
11
|
-
require_relative "gemba/save_state_manager"
|
|
12
|
-
require_relative "gemba/toast_overlay"
|
|
13
|
-
require_relative "gemba/overlay_renderer"
|
|
14
|
-
require_relative "gemba/input_mappings"
|
|
15
|
-
require_relative "gemba/hotkey_map"
|
|
16
|
-
require_relative "gemba/recorder"
|
|
17
|
-
require_relative "gemba/player"
|
|
7
|
+
require_relative "gemba/platform_open"
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require_relative "../shared/tk_test_helper"
|
|
5
|
+
|
|
6
|
+
# Tests for AchievementsWindow bulk sync — unofficial toggle fires bus event,
|
|
7
|
+
# UI locks/unlocks during sync, per-game status updates, and done count display.
|
|
8
|
+
class TestAchievementsWindowBulkSync < Minitest::Test
|
|
9
|
+
include TeekTestHelper
|
|
10
|
+
|
|
11
|
+
def test_unofficial_toggle_fires_bus_event
|
|
12
|
+
assert_tk_app("toggling unofficial checkbox fires :ra_unofficial_changed on the bus") do
|
|
13
|
+
begin
|
|
14
|
+
require "gemba/headless"
|
|
15
|
+
require "support/achievements_window_helpers"
|
|
16
|
+
require "tmpdir"
|
|
17
|
+
Gemba.bus = Gemba::EventBus.new
|
|
18
|
+
|
|
19
|
+
received = nil
|
|
20
|
+
Gemba.bus.on(:ra_unofficial_changed) { |value:, **| received = value }
|
|
21
|
+
|
|
22
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
23
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
24
|
+
backend.stub_fetch_for_display([])
|
|
25
|
+
|
|
26
|
+
Dir.mktmpdir("ach_win_test") do |tmpdir|
|
|
27
|
+
ENV['GEMBA_CONFIG_DIR'] = tmpdir
|
|
28
|
+
win = Gemba::AchievementsWindow.new(
|
|
29
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
30
|
+
)
|
|
31
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
32
|
+
win.show
|
|
33
|
+
app.update
|
|
34
|
+
|
|
35
|
+
top = Gemba::AchievementsWindow::TOP
|
|
36
|
+
app.command("#{top}.toolbar.unofficial", 'invoke')
|
|
37
|
+
app.update
|
|
38
|
+
|
|
39
|
+
assert_equal true, received, ":ra_unofficial_changed should fire with true"
|
|
40
|
+
ensure
|
|
41
|
+
ENV.delete('GEMBA_CONFIG_DIR')
|
|
42
|
+
end
|
|
43
|
+
ensure
|
|
44
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def test_unofficial_toggle_locks_ui_during_sync
|
|
50
|
+
assert_tk_app("unofficial toggle disables both buttons while bulk sync runs") do
|
|
51
|
+
begin
|
|
52
|
+
require "gemba/headless"
|
|
53
|
+
require "support/achievements_window_helpers"
|
|
54
|
+
require "tmpdir"
|
|
55
|
+
Gemba.bus = Gemba::EventBus.new
|
|
56
|
+
|
|
57
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
58
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
59
|
+
|
|
60
|
+
# Capture widget states from INSIDE the fetch callback — FakeBackend
|
|
61
|
+
# calls synchronously so we're mid-sync right here.
|
|
62
|
+
mid_sync_states = {}
|
|
63
|
+
backend.stub_fetch_for_display do |_|
|
|
64
|
+
top = Gemba::AchievementsWindow::TOP
|
|
65
|
+
mid_sync_states[:sync] = app.command("#{top}.toolbar.sync", :cget, '-state').to_s
|
|
66
|
+
mid_sync_states[:unoff] = app.command("#{top}.toolbar.unofficial", :cget, '-state').to_s
|
|
67
|
+
nil
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
roms = [make_rom_entry(id: 'r1', title: 'Game')]
|
|
71
|
+
Dir.mktmpdir("ach_win_test") do |tmpdir|
|
|
72
|
+
ENV['GEMBA_CONFIG_DIR'] = tmpdir
|
|
73
|
+
win = Gemba::AchievementsWindow.new(
|
|
74
|
+
app: app, rom_library: make_rom_library(*roms), config: FakeConfig.new(false)
|
|
75
|
+
)
|
|
76
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
77
|
+
win.show
|
|
78
|
+
app.update
|
|
79
|
+
|
|
80
|
+
top = Gemba::AchievementsWindow::TOP
|
|
81
|
+
app.command("#{top}.toolbar.unofficial", 'invoke')
|
|
82
|
+
app.update
|
|
83
|
+
|
|
84
|
+
assert_equal 'disabled', mid_sync_states[:sync], "sync button locked during bulk sync"
|
|
85
|
+
assert_equal 'disabled', mid_sync_states[:unoff], "unofficial button locked during bulk sync"
|
|
86
|
+
ensure
|
|
87
|
+
ENV.delete('GEMBA_CONFIG_DIR')
|
|
88
|
+
end
|
|
89
|
+
ensure
|
|
90
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def test_bulk_sync_shows_per_game_status_updates
|
|
96
|
+
assert_tk_app("bulk sync updates the status bar for each game in sequence") do
|
|
97
|
+
begin
|
|
98
|
+
require "gemba/headless"
|
|
99
|
+
require "support/achievements_window_helpers"
|
|
100
|
+
require "tmpdir"
|
|
101
|
+
Gemba.bus = Gemba::EventBus.new
|
|
102
|
+
|
|
103
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
104
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
105
|
+
|
|
106
|
+
statuses = []
|
|
107
|
+
backend.stub_fetch_for_display do |_|
|
|
108
|
+
top = Gemba::AchievementsWindow::TOP
|
|
109
|
+
statuses << app.command("#{top}.status_bar.status", :cget, '-text').to_s
|
|
110
|
+
[]
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
roms = [
|
|
114
|
+
make_rom_entry(id: 'r1', title: 'Game One'),
|
|
115
|
+
make_rom_entry(id: 'r2', title: 'Game Two'),
|
|
116
|
+
]
|
|
117
|
+
Dir.mktmpdir("ach_win_test") do |tmpdir|
|
|
118
|
+
ENV['GEMBA_CONFIG_DIR'] = tmpdir
|
|
119
|
+
win = Gemba::AchievementsWindow.new(
|
|
120
|
+
app: app, rom_library: make_rom_library(*roms), config: FakeConfig.new(false)
|
|
121
|
+
)
|
|
122
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
123
|
+
win.show
|
|
124
|
+
app.update
|
|
125
|
+
|
|
126
|
+
top = Gemba::AchievementsWindow::TOP
|
|
127
|
+
app.command("#{top}.toolbar.unofficial", 'invoke')
|
|
128
|
+
app.update
|
|
129
|
+
|
|
130
|
+
assert_equal 2, statuses.size, "one status update per game"
|
|
131
|
+
assert_includes statuses[0], 'Game One', "first update names Game One"
|
|
132
|
+
assert_includes statuses[1], 'Game Two', "second update names Game Two"
|
|
133
|
+
ensure
|
|
134
|
+
ENV.delete('GEMBA_CONFIG_DIR')
|
|
135
|
+
end
|
|
136
|
+
ensure
|
|
137
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def test_bulk_sync_unlocks_ui_when_complete
|
|
143
|
+
assert_tk_app("bulk sync re-enables buttons after all games are done") do
|
|
144
|
+
begin
|
|
145
|
+
require "gemba/headless"
|
|
146
|
+
require "support/achievements_window_helpers"
|
|
147
|
+
require "tmpdir"
|
|
148
|
+
Gemba.bus = Gemba::EventBus.new
|
|
149
|
+
|
|
150
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
151
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
152
|
+
backend.stub_fetch_for_display([])
|
|
153
|
+
|
|
154
|
+
roms = [make_rom_entry(id: 'r1', title: 'Game')]
|
|
155
|
+
Dir.mktmpdir("ach_win_test") do |tmpdir|
|
|
156
|
+
ENV['GEMBA_CONFIG_DIR'] = tmpdir
|
|
157
|
+
win = Gemba::AchievementsWindow.new(
|
|
158
|
+
app: app, rom_library: make_rom_library(*roms), config: FakeConfig.new(false)
|
|
159
|
+
)
|
|
160
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
161
|
+
win.show
|
|
162
|
+
app.update
|
|
163
|
+
|
|
164
|
+
top = Gemba::AchievementsWindow::TOP
|
|
165
|
+
app.command("#{top}.toolbar.unofficial", 'invoke')
|
|
166
|
+
app.update
|
|
167
|
+
|
|
168
|
+
assert_equal 'normal', app.command("#{top}.toolbar.sync", :cget, '-state').to_s
|
|
169
|
+
assert_equal 'normal', app.command("#{top}.toolbar.unofficial", :cget, '-state').to_s
|
|
170
|
+
ensure
|
|
171
|
+
ENV.delete('GEMBA_CONFIG_DIR')
|
|
172
|
+
end
|
|
173
|
+
ensure
|
|
174
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def test_bulk_sync_done_status_shows_count
|
|
180
|
+
assert_tk_app("status bar shows N-game count after bulk sync completes") do
|
|
181
|
+
begin
|
|
182
|
+
require "gemba/headless"
|
|
183
|
+
require "support/achievements_window_helpers"
|
|
184
|
+
require "tmpdir"
|
|
185
|
+
Gemba.bus = Gemba::EventBus.new
|
|
186
|
+
|
|
187
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
188
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
189
|
+
backend.stub_fetch_for_display([])
|
|
190
|
+
|
|
191
|
+
roms = [
|
|
192
|
+
make_rom_entry(id: 'r1', title: 'Game A'),
|
|
193
|
+
make_rom_entry(id: 'r2', title: 'Game B'),
|
|
194
|
+
]
|
|
195
|
+
Dir.mktmpdir("ach_win_test") do |tmpdir|
|
|
196
|
+
ENV['GEMBA_CONFIG_DIR'] = tmpdir
|
|
197
|
+
win = Gemba::AchievementsWindow.new(
|
|
198
|
+
app: app, rom_library: make_rom_library(*roms), config: FakeConfig.new(false)
|
|
199
|
+
)
|
|
200
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
201
|
+
win.show
|
|
202
|
+
app.update
|
|
203
|
+
|
|
204
|
+
top = Gemba::AchievementsWindow::TOP
|
|
205
|
+
app.command("#{top}.toolbar.unofficial", 'invoke')
|
|
206
|
+
app.update
|
|
207
|
+
|
|
208
|
+
status = app.command("#{top}.status_bar.status", :cget, '-text').to_s
|
|
209
|
+
assert_includes status, '2', "done status should mention 2 games synced"
|
|
210
|
+
ensure
|
|
211
|
+
ENV.delete('GEMBA_CONFIG_DIR')
|
|
212
|
+
end
|
|
213
|
+
ensure
|
|
214
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require_relative "../shared/tk_test_helper"
|
|
5
|
+
|
|
6
|
+
# Tests for AchievementsWindow event bus subscriptions — sync started/done
|
|
7
|
+
# disables/enables the sync button and auth-result logout disables it.
|
|
8
|
+
class TestAchievementsWindowBusEvents < Minitest::Test
|
|
9
|
+
include TeekTestHelper
|
|
10
|
+
|
|
11
|
+
def test_ra_sync_started_disables_sync_button
|
|
12
|
+
assert_tk_app(":ra_sync_started disables the sync button") do
|
|
13
|
+
begin
|
|
14
|
+
require "gemba/headless"
|
|
15
|
+
require "support/achievements_window_helpers"
|
|
16
|
+
Gemba.bus = Gemba::EventBus.new
|
|
17
|
+
|
|
18
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
19
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
20
|
+
win = Gemba::AchievementsWindow.new(
|
|
21
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
22
|
+
)
|
|
23
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
24
|
+
win.show
|
|
25
|
+
app.update
|
|
26
|
+
|
|
27
|
+
Gemba.bus.emit(:ra_sync_started)
|
|
28
|
+
app.update
|
|
29
|
+
|
|
30
|
+
top = Gemba::AchievementsWindow::TOP
|
|
31
|
+
assert_equal 'disabled',
|
|
32
|
+
app.command("#{top}.toolbar.sync", :cget, '-state').to_s
|
|
33
|
+
ensure
|
|
34
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_ra_sync_done_ok_re_enables_sync_button
|
|
40
|
+
assert_tk_app(":ra_sync_done(ok: true) re-enables the sync button") do
|
|
41
|
+
begin
|
|
42
|
+
require "gemba/headless"
|
|
43
|
+
require "support/achievements_window_helpers"
|
|
44
|
+
Gemba.bus = Gemba::EventBus.new
|
|
45
|
+
|
|
46
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
47
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
48
|
+
win = Gemba::AchievementsWindow.new(
|
|
49
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
50
|
+
)
|
|
51
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
52
|
+
win.show
|
|
53
|
+
app.update
|
|
54
|
+
|
|
55
|
+
Gemba.bus.emit(:ra_sync_started)
|
|
56
|
+
app.update
|
|
57
|
+
Gemba.bus.emit(:ra_sync_done, ok: true)
|
|
58
|
+
app.update
|
|
59
|
+
|
|
60
|
+
top = Gemba::AchievementsWindow::TOP
|
|
61
|
+
assert_equal 'normal',
|
|
62
|
+
app.command("#{top}.toolbar.sync", :cget, '-state').to_s
|
|
63
|
+
ensure
|
|
64
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_ra_sync_done_fail_shows_error_status
|
|
70
|
+
assert_tk_app(":ra_sync_done(ok: false) shows sync_failed in status bar") do
|
|
71
|
+
begin
|
|
72
|
+
require "gemba/headless"
|
|
73
|
+
require "support/achievements_window_helpers"
|
|
74
|
+
Gemba.bus = Gemba::EventBus.new
|
|
75
|
+
|
|
76
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
77
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
78
|
+
win = Gemba::AchievementsWindow.new(
|
|
79
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
80
|
+
)
|
|
81
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
82
|
+
win.show
|
|
83
|
+
app.update
|
|
84
|
+
|
|
85
|
+
Gemba.bus.emit(:ra_sync_done, ok: false)
|
|
86
|
+
app.update
|
|
87
|
+
|
|
88
|
+
top = Gemba::AchievementsWindow::TOP
|
|
89
|
+
status = app.command("#{top}.status_bar.status", :cget, '-text').to_s
|
|
90
|
+
assert_equal Gemba::Locale.translate('achievements.sync_failed'), status
|
|
91
|
+
ensure
|
|
92
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def test_ra_auth_result_logout_disables_sync_button
|
|
98
|
+
assert_tk_app(":ra_auth_result after logout disables sync button") do
|
|
99
|
+
begin
|
|
100
|
+
require "gemba/headless"
|
|
101
|
+
require "support/achievements_window_helpers"
|
|
102
|
+
Gemba.bus = Gemba::EventBus.new
|
|
103
|
+
|
|
104
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
105
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
106
|
+
win = Gemba::AchievementsWindow.new(
|
|
107
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
108
|
+
)
|
|
109
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
110
|
+
win.show
|
|
111
|
+
app.update
|
|
112
|
+
|
|
113
|
+
backend.logout
|
|
114
|
+
Gemba.bus.emit(:ra_auth_result, status: :logout)
|
|
115
|
+
app.update
|
|
116
|
+
|
|
117
|
+
top = Gemba::AchievementsWindow::TOP
|
|
118
|
+
assert_equal 'disabled',
|
|
119
|
+
app.command("#{top}.toolbar.sync", :cget, '-state').to_s
|
|
120
|
+
ensure
|
|
121
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require_relative "../shared/tk_test_helper"
|
|
5
|
+
|
|
6
|
+
# Tests for AchievementsWindow close-during-bulk-sync confirmation dialog —
|
|
7
|
+
# no dialog when not syncing, dialog shown mid-sync, 'no' keeps window open,
|
|
8
|
+
# 'yes' stops sync and withdraws the window.
|
|
9
|
+
class TestAchievementsWindowCloseConfirmation < Minitest::Test
|
|
10
|
+
include TeekTestHelper
|
|
11
|
+
|
|
12
|
+
def test_hide_without_bulk_sync_does_not_show_dialog
|
|
13
|
+
assert_tk_app("win.hide when not syncing closes without showing any dialog") do
|
|
14
|
+
begin
|
|
15
|
+
require "gemba/headless"
|
|
16
|
+
require "support/achievements_window_helpers"
|
|
17
|
+
Gemba.bus = Gemba::EventBus.new
|
|
18
|
+
|
|
19
|
+
app.tcl_eval("set ::ach_dlg 0")
|
|
20
|
+
app.tcl_eval("proc tk_messageBox {args} { incr ::ach_dlg; return yes }")
|
|
21
|
+
|
|
22
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
23
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
24
|
+
win = Gemba::AchievementsWindow.new(
|
|
25
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
26
|
+
)
|
|
27
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
28
|
+
win.show
|
|
29
|
+
app.update
|
|
30
|
+
|
|
31
|
+
win.hide
|
|
32
|
+
app.update
|
|
33
|
+
|
|
34
|
+
assert_equal '0', app.tcl_eval("set ::ach_dlg").strip,
|
|
35
|
+
"tk_messageBox must not be called when not in bulk sync"
|
|
36
|
+
ensure
|
|
37
|
+
app.tcl_eval("catch {rename tk_messageBox {}}") rescue nil
|
|
38
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_hide_during_bulk_sync_shows_dialog
|
|
44
|
+
assert_tk_app("win.hide mid-sync triggers a tk_messageBox confirmation") do
|
|
45
|
+
begin
|
|
46
|
+
require "gemba/headless"
|
|
47
|
+
require "support/achievements_window_helpers"
|
|
48
|
+
require "tmpdir"
|
|
49
|
+
Gemba.bus = Gemba::EventBus.new
|
|
50
|
+
|
|
51
|
+
app.tcl_eval("set ::ach_dlg 0")
|
|
52
|
+
app.tcl_eval("proc tk_messageBox {args} { incr ::ach_dlg; return no }")
|
|
53
|
+
|
|
54
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
55
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
56
|
+
|
|
57
|
+
win = nil
|
|
58
|
+
attempted = false
|
|
59
|
+
backend.stub_fetch_for_display do |_|
|
|
60
|
+
unless attempted
|
|
61
|
+
attempted = true
|
|
62
|
+
win.hide # dialog returns "no" → stays open
|
|
63
|
+
app.update
|
|
64
|
+
end
|
|
65
|
+
nil
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
roms = [make_rom_entry(id: 'r1', title: 'Game')]
|
|
69
|
+
Dir.mktmpdir("ach_win_test") do |tmpdir|
|
|
70
|
+
ENV['GEMBA_CONFIG_DIR'] = tmpdir
|
|
71
|
+
win = Gemba::AchievementsWindow.new(
|
|
72
|
+
app: app, rom_library: make_rom_library(*roms), config: FakeConfig.new(false)
|
|
73
|
+
)
|
|
74
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
75
|
+
win.show
|
|
76
|
+
app.update
|
|
77
|
+
|
|
78
|
+
top = Gemba::AchievementsWindow::TOP
|
|
79
|
+
app.command("#{top}.toolbar.unofficial", 'invoke')
|
|
80
|
+
app.update
|
|
81
|
+
|
|
82
|
+
assert_equal '1', app.tcl_eval("set ::ach_dlg").strip,
|
|
83
|
+
"tk_messageBox must be shown when hiding during bulk sync"
|
|
84
|
+
ensure
|
|
85
|
+
ENV.delete('GEMBA_CONFIG_DIR')
|
|
86
|
+
end
|
|
87
|
+
ensure
|
|
88
|
+
app.tcl_eval("catch {rename tk_messageBox {}}") rescue nil
|
|
89
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def test_hide_confirm_no_keeps_window_visible
|
|
95
|
+
assert_tk_app("answering 'no' to the cancel-sync dialog keeps the window open") do
|
|
96
|
+
begin
|
|
97
|
+
require "gemba/headless"
|
|
98
|
+
require "support/achievements_window_helpers"
|
|
99
|
+
require "tmpdir"
|
|
100
|
+
Gemba.bus = Gemba::EventBus.new
|
|
101
|
+
|
|
102
|
+
app.tcl_eval("proc tk_messageBox {args} { return no }")
|
|
103
|
+
|
|
104
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
105
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
106
|
+
|
|
107
|
+
win = nil
|
|
108
|
+
attempted = false
|
|
109
|
+
backend.stub_fetch_for_display do |_|
|
|
110
|
+
unless attempted
|
|
111
|
+
attempted = true
|
|
112
|
+
win.hide
|
|
113
|
+
app.update
|
|
114
|
+
end
|
|
115
|
+
nil
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
roms = [make_rom_entry(id: 'r1', title: 'Game')]
|
|
119
|
+
Dir.mktmpdir("ach_win_test") do |tmpdir|
|
|
120
|
+
ENV['GEMBA_CONFIG_DIR'] = tmpdir
|
|
121
|
+
win = Gemba::AchievementsWindow.new(
|
|
122
|
+
app: app, rom_library: make_rom_library(*roms), config: FakeConfig.new(false)
|
|
123
|
+
)
|
|
124
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
125
|
+
win.show
|
|
126
|
+
app.update
|
|
127
|
+
|
|
128
|
+
top = Gemba::AchievementsWindow::TOP
|
|
129
|
+
app.command("#{top}.toolbar.unofficial", 'invoke')
|
|
130
|
+
app.update
|
|
131
|
+
|
|
132
|
+
# wm state is unreliable in xvfb when the root is withdrawn; instead
|
|
133
|
+
# verify the sync completed and UI was unlocked — only possible if
|
|
134
|
+
# the window stayed open and the sync ran to completion.
|
|
135
|
+
assert_equal 'normal', app.command("#{top}.toolbar.sync", :cget, '-state').to_s,
|
|
136
|
+
"sync button must be re-enabled after sync completes (window stayed open)"
|
|
137
|
+
ensure
|
|
138
|
+
ENV.delete('GEMBA_CONFIG_DIR')
|
|
139
|
+
end
|
|
140
|
+
ensure
|
|
141
|
+
app.tcl_eval("catch {rename tk_messageBox {}}") rescue nil
|
|
142
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def test_hide_confirm_yes_stops_sync_and_withdraws_window
|
|
148
|
+
assert_tk_app("answering 'yes' stops the bulk sync and withdraws the window") do
|
|
149
|
+
begin
|
|
150
|
+
require "gemba/headless"
|
|
151
|
+
require "support/achievements_window_helpers"
|
|
152
|
+
require "tmpdir"
|
|
153
|
+
Gemba.bus = Gemba::EventBus.new
|
|
154
|
+
|
|
155
|
+
app.tcl_eval("proc tk_messageBox {args} { return yes }")
|
|
156
|
+
|
|
157
|
+
win = nil
|
|
158
|
+
fetch_count = 0
|
|
159
|
+
hide_done = false
|
|
160
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
161
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
162
|
+
backend.stub_fetch_for_display do |_|
|
|
163
|
+
fetch_count += 1
|
|
164
|
+
unless hide_done
|
|
165
|
+
hide_done = true
|
|
166
|
+
win.hide # dialog returns "yes" → cancel + withdraw
|
|
167
|
+
app.update
|
|
168
|
+
end
|
|
169
|
+
nil
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
roms = [
|
|
173
|
+
make_rom_entry(id: 'r1', title: 'Game One'),
|
|
174
|
+
make_rom_entry(id: 'r2', title: 'Game Two'),
|
|
175
|
+
]
|
|
176
|
+
Dir.mktmpdir("ach_win_test") do |tmpdir|
|
|
177
|
+
ENV['GEMBA_CONFIG_DIR'] = tmpdir
|
|
178
|
+
win = Gemba::AchievementsWindow.new(
|
|
179
|
+
app: app, rom_library: make_rom_library(*roms), config: FakeConfig.new(false)
|
|
180
|
+
)
|
|
181
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
182
|
+
win.show
|
|
183
|
+
app.update
|
|
184
|
+
|
|
185
|
+
top = Gemba::AchievementsWindow::TOP
|
|
186
|
+
app.command("#{top}.toolbar.unofficial", 'invoke')
|
|
187
|
+
app.update
|
|
188
|
+
|
|
189
|
+
assert_equal 1, fetch_count, "sync must stop after the first game when user says yes"
|
|
190
|
+
assert_equal 'withdrawn', app.tcl_eval("wm state #{top}").strip,
|
|
191
|
+
"window must be withdrawn after user confirms close"
|
|
192
|
+
ensure
|
|
193
|
+
ENV.delete('GEMBA_CONFIG_DIR')
|
|
194
|
+
end
|
|
195
|
+
ensure
|
|
196
|
+
app.tcl_eval("catch {rename tk_messageBox {}}") rescue nil
|
|
197
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|