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
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require_relative "../shared/tk_test_helper"
|
|
5
|
+
|
|
6
|
+
# Tests for AchievementsWindow initial widget state — sync button, unofficial
|
|
7
|
+
# checkbox, game combo filter, and status bar default text.
|
|
8
|
+
class TestAchievementsWindowInitialState < Minitest::Test
|
|
9
|
+
include TeekTestHelper
|
|
10
|
+
|
|
11
|
+
TOP = Gemba::AchievementsWindow::TOP rescue '.gemba_achievements'
|
|
12
|
+
|
|
13
|
+
def test_sync_button_disabled_when_not_authenticated
|
|
14
|
+
assert_tk_app("sync button disabled when not authenticated") do
|
|
15
|
+
begin
|
|
16
|
+
require "gemba/headless"
|
|
17
|
+
require "support/achievements_window_helpers"
|
|
18
|
+
Gemba.bus = Gemba::EventBus.new
|
|
19
|
+
|
|
20
|
+
backend = Gemba::Achievements::FakeBackend.new # NOT logged in
|
|
21
|
+
win = Gemba::AchievementsWindow.new(
|
|
22
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
23
|
+
)
|
|
24
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
25
|
+
win.show
|
|
26
|
+
app.update
|
|
27
|
+
|
|
28
|
+
top = Gemba::AchievementsWindow::TOP
|
|
29
|
+
assert_equal 'disabled',
|
|
30
|
+
app.command("#{top}.toolbar.sync", :cget, '-state').to_s
|
|
31
|
+
ensure
|
|
32
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_sync_button_enabled_when_authenticated
|
|
38
|
+
assert_tk_app("sync button enabled when authenticated") do
|
|
39
|
+
begin
|
|
40
|
+
require "gemba/headless"
|
|
41
|
+
require "support/achievements_window_helpers"
|
|
42
|
+
Gemba.bus = Gemba::EventBus.new
|
|
43
|
+
|
|
44
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
45
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
46
|
+
win = Gemba::AchievementsWindow.new(
|
|
47
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
48
|
+
)
|
|
49
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
50
|
+
win.show
|
|
51
|
+
app.update
|
|
52
|
+
|
|
53
|
+
top = Gemba::AchievementsWindow::TOP
|
|
54
|
+
assert_equal 'normal',
|
|
55
|
+
app.command("#{top}.toolbar.sync", :cget, '-state').to_s
|
|
56
|
+
ensure
|
|
57
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def test_unofficial_checkbox_reflects_config_false
|
|
63
|
+
assert_tk_app("unofficial checkbox is unchecked when config is false") do
|
|
64
|
+
begin
|
|
65
|
+
require "gemba/headless"
|
|
66
|
+
require "support/achievements_window_helpers"
|
|
67
|
+
Gemba.bus = Gemba::EventBus.new
|
|
68
|
+
|
|
69
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
70
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
71
|
+
win = Gemba::AchievementsWindow.new(
|
|
72
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
73
|
+
)
|
|
74
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
75
|
+
win.show
|
|
76
|
+
app.update
|
|
77
|
+
|
|
78
|
+
assert_equal '0', app.get_variable(Gemba::AchievementsWindow::VAR_UNOFFICIAL)
|
|
79
|
+
ensure
|
|
80
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def test_unofficial_checkbox_reflects_config_true
|
|
86
|
+
assert_tk_app("unofficial checkbox is checked when config is true") do
|
|
87
|
+
begin
|
|
88
|
+
require "gemba/headless"
|
|
89
|
+
require "support/achievements_window_helpers"
|
|
90
|
+
Gemba.bus = Gemba::EventBus.new
|
|
91
|
+
|
|
92
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
93
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
94
|
+
win = Gemba::AchievementsWindow.new(
|
|
95
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(true)
|
|
96
|
+
)
|
|
97
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
98
|
+
win.show
|
|
99
|
+
app.update
|
|
100
|
+
|
|
101
|
+
assert_equal '1', app.get_variable(Gemba::AchievementsWindow::VAR_UNOFFICIAL)
|
|
102
|
+
ensure
|
|
103
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def test_combo_shows_only_gba_games
|
|
109
|
+
assert_tk_app("combo lists GBA games only, not GB or GBC") do
|
|
110
|
+
begin
|
|
111
|
+
require "gemba/headless"
|
|
112
|
+
require "support/achievements_window_helpers"
|
|
113
|
+
Gemba.bus = Gemba::EventBus.new
|
|
114
|
+
|
|
115
|
+
roms = [
|
|
116
|
+
make_rom_entry(id: 'gba1', title: 'GBA Game', platform: 'gba'),
|
|
117
|
+
make_rom_entry(id: 'gb1', title: 'GB Game', platform: 'gb'),
|
|
118
|
+
make_rom_entry(id: 'gbc1', title: 'GBC Game', platform: 'gbc'),
|
|
119
|
+
]
|
|
120
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
121
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
122
|
+
win = Gemba::AchievementsWindow.new(
|
|
123
|
+
app: app, rom_library: make_rom_library(*roms), config: FakeConfig.new(false)
|
|
124
|
+
)
|
|
125
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
126
|
+
win.show
|
|
127
|
+
app.update
|
|
128
|
+
|
|
129
|
+
top = Gemba::AchievementsWindow::TOP
|
|
130
|
+
values = app.command("#{top}.toolbar.combo", :cget, '-values').to_s
|
|
131
|
+
assert_includes values, 'GBA Game'
|
|
132
|
+
refute_includes values, 'GB Game'
|
|
133
|
+
refute_includes values, 'GBC Game'
|
|
134
|
+
ensure
|
|
135
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def test_status_shows_none_when_empty
|
|
141
|
+
assert_tk_app("status shows 'no achievements' when backend has no achievements") do
|
|
142
|
+
begin
|
|
143
|
+
require "gemba/headless"
|
|
144
|
+
require "support/achievements_window_helpers"
|
|
145
|
+
Gemba.bus = Gemba::EventBus.new
|
|
146
|
+
|
|
147
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
148
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
149
|
+
win = Gemba::AchievementsWindow.new(
|
|
150
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
151
|
+
)
|
|
152
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
153
|
+
win.show
|
|
154
|
+
app.update
|
|
155
|
+
|
|
156
|
+
top = Gemba::AchievementsWindow::TOP
|
|
157
|
+
status = app.command("#{top}.status_bar.status", :cget, '-text').to_s
|
|
158
|
+
assert_equal Gemba::Locale.translate('achievements.none'), status
|
|
159
|
+
ensure
|
|
160
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require_relative "../shared/tk_test_helper"
|
|
5
|
+
|
|
6
|
+
# Tests for AchievementsWindow treeview column sorting — default order,
|
|
7
|
+
# heading click indicators, and indicator cleanup when switching columns.
|
|
8
|
+
class TestAchievementsWindowSorting < Minitest::Test
|
|
9
|
+
include TeekTestHelper
|
|
10
|
+
|
|
11
|
+
def test_default_sort_earned_first_then_alphabetical
|
|
12
|
+
assert_tk_app("default sort: earned first, then unearned A→Z") do
|
|
13
|
+
begin
|
|
14
|
+
require "gemba/headless"
|
|
15
|
+
require "support/achievements_window_helpers"
|
|
16
|
+
require "support/fake_core"
|
|
17
|
+
Gemba.bus = Gemba::EventBus.new
|
|
18
|
+
|
|
19
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
20
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
21
|
+
backend.add_achievement(id: 'z', title: 'Zebra', description: '', points: 5) { false }
|
|
22
|
+
backend.add_achievement(id: 'a', title: 'Aardvark', description: '', points: 5) { |_| true }
|
|
23
|
+
backend.add_achievement(id: 'm', title: 'Monkey', description: '', points: 5) { false }
|
|
24
|
+
backend.do_frame(FakeCore.new)
|
|
25
|
+
|
|
26
|
+
win = Gemba::AchievementsWindow.new(
|
|
27
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
28
|
+
)
|
|
29
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
30
|
+
win.show
|
|
31
|
+
win.refresh(backend)
|
|
32
|
+
app.update
|
|
33
|
+
|
|
34
|
+
tree = "#{Gemba::AchievementsWindow::TOP}.tf.tree"
|
|
35
|
+
items = app.tcl_eval("#{tree} children {}").split
|
|
36
|
+
titles = items.map { |id| app.tcl_eval("#{tree} set #{id} name") }
|
|
37
|
+
assert_equal 'Aardvark', titles[0], "earned should be first"
|
|
38
|
+
assert_equal 'Monkey', titles[1], "Monkey before Zebra alphabetically"
|
|
39
|
+
assert_equal 'Zebra', titles[2]
|
|
40
|
+
ensure
|
|
41
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_click_name_heading_sorts_asc_with_indicator
|
|
47
|
+
assert_tk_app("clicking name heading sorts A→Z and shows ▲") do
|
|
48
|
+
begin
|
|
49
|
+
require "gemba/headless"
|
|
50
|
+
require "support/achievements_window_helpers"
|
|
51
|
+
Gemba.bus = Gemba::EventBus.new
|
|
52
|
+
|
|
53
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
54
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
55
|
+
backend.add_achievement(id: 'z', title: 'Zebra', description: '', points: 5) { false }
|
|
56
|
+
backend.add_achievement(id: 'a', title: 'Aardvark', description: '', points: 5) { false }
|
|
57
|
+
backend.add_achievement(id: 'm', title: 'Monkey', description: '', points: 5) { false }
|
|
58
|
+
|
|
59
|
+
win = Gemba::AchievementsWindow.new(
|
|
60
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
61
|
+
)
|
|
62
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
63
|
+
win.show
|
|
64
|
+
win.refresh(backend)
|
|
65
|
+
app.update
|
|
66
|
+
|
|
67
|
+
tree = "#{Gemba::AchievementsWindow::TOP}.tf.tree"
|
|
68
|
+
cmd = app.tcl_eval("#{tree} heading name -command")
|
|
69
|
+
app.tcl_eval("uplevel #0 {#{cmd}}")
|
|
70
|
+
app.update
|
|
71
|
+
|
|
72
|
+
items = app.tcl_eval("#{tree} children {}").split
|
|
73
|
+
titles = items.map { |id| app.tcl_eval("#{tree} set #{id} name") }
|
|
74
|
+
assert_equal %w[Aardvark Monkey Zebra], titles
|
|
75
|
+
|
|
76
|
+
assert_includes app.tcl_eval("#{tree} heading name -text"), '▲'
|
|
77
|
+
ensure
|
|
78
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def test_click_name_heading_twice_reverses_to_desc
|
|
84
|
+
assert_tk_app("clicking name heading twice reverses to Z→A and shows ▼") do
|
|
85
|
+
begin
|
|
86
|
+
require "gemba/headless"
|
|
87
|
+
require "support/achievements_window_helpers"
|
|
88
|
+
Gemba.bus = Gemba::EventBus.new
|
|
89
|
+
|
|
90
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
91
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
92
|
+
backend.add_achievement(id: 'z', title: 'Zebra', description: '', points: 5) { false }
|
|
93
|
+
backend.add_achievement(id: 'a', title: 'Aardvark', description: '', points: 5) { false }
|
|
94
|
+
|
|
95
|
+
win = Gemba::AchievementsWindow.new(
|
|
96
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
97
|
+
)
|
|
98
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
99
|
+
win.show
|
|
100
|
+
win.refresh(backend)
|
|
101
|
+
app.update
|
|
102
|
+
|
|
103
|
+
tree = "#{Gemba::AchievementsWindow::TOP}.tf.tree"
|
|
104
|
+
cmd = app.tcl_eval("#{tree} heading name -command")
|
|
105
|
+
app.tcl_eval("uplevel #0 {#{cmd}}") # asc
|
|
106
|
+
app.tcl_eval("uplevel #0 {#{cmd}}") # desc
|
|
107
|
+
app.update
|
|
108
|
+
|
|
109
|
+
items = app.tcl_eval("#{tree} children {}").split
|
|
110
|
+
titles = items.map { |id| app.tcl_eval("#{tree} set #{id} name") }
|
|
111
|
+
assert_equal %w[Zebra Aardvark], titles
|
|
112
|
+
assert_includes app.tcl_eval("#{tree} heading name -text"), '▼'
|
|
113
|
+
ensure
|
|
114
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def test_click_points_heading_sorts_low_to_high
|
|
120
|
+
assert_tk_app("clicking points heading sorts by points low→high") do
|
|
121
|
+
begin
|
|
122
|
+
require "gemba/headless"
|
|
123
|
+
require "support/achievements_window_helpers"
|
|
124
|
+
Gemba.bus = Gemba::EventBus.new
|
|
125
|
+
|
|
126
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
127
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
128
|
+
backend.add_achievement(id: 'a', title: 'High', description: '', points: 50) { false }
|
|
129
|
+
backend.add_achievement(id: 'b', title: 'Low', description: '', points: 5) { false }
|
|
130
|
+
backend.add_achievement(id: 'c', title: 'Mid', description: '', points: 25) { false }
|
|
131
|
+
|
|
132
|
+
win = Gemba::AchievementsWindow.new(
|
|
133
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
134
|
+
)
|
|
135
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
136
|
+
win.show
|
|
137
|
+
win.refresh(backend)
|
|
138
|
+
app.update
|
|
139
|
+
|
|
140
|
+
tree = "#{Gemba::AchievementsWindow::TOP}.tf.tree"
|
|
141
|
+
cmd = app.tcl_eval("#{tree} heading points -command")
|
|
142
|
+
app.tcl_eval("uplevel #0 {#{cmd}}")
|
|
143
|
+
app.update
|
|
144
|
+
|
|
145
|
+
items = app.tcl_eval("#{tree} children {}").split
|
|
146
|
+
pts = items.map { |id| app.tcl_eval("#{tree} set #{id} points").to_i }
|
|
147
|
+
assert_equal [5, 25, 50], pts
|
|
148
|
+
ensure
|
|
149
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def test_click_earned_heading_puts_unearned_last
|
|
155
|
+
assert_tk_app("clicking earned heading keeps unearned rows at the bottom") do
|
|
156
|
+
begin
|
|
157
|
+
require "gemba/headless"
|
|
158
|
+
require "support/achievements_window_helpers"
|
|
159
|
+
require "support/fake_core"
|
|
160
|
+
Gemba.bus = Gemba::EventBus.new
|
|
161
|
+
|
|
162
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
163
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
164
|
+
backend.add_achievement(id: 'e', title: 'Earned', description: '', points: 5) { |_| true }
|
|
165
|
+
backend.add_achievement(id: 'u', title: 'Unearned', description: '', points: 5) { false }
|
|
166
|
+
backend.do_frame(FakeCore.new)
|
|
167
|
+
|
|
168
|
+
win = Gemba::AchievementsWindow.new(
|
|
169
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
170
|
+
)
|
|
171
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
172
|
+
win.show
|
|
173
|
+
win.refresh(backend)
|
|
174
|
+
app.update
|
|
175
|
+
|
|
176
|
+
tree = "#{Gemba::AchievementsWindow::TOP}.tf.tree"
|
|
177
|
+
cmd = app.tcl_eval("#{tree} heading earned -command")
|
|
178
|
+
app.tcl_eval("uplevel #0 {#{cmd}}")
|
|
179
|
+
app.update
|
|
180
|
+
|
|
181
|
+
items = app.tcl_eval("#{tree} children {}").split
|
|
182
|
+
earned = items.map { |id| app.tcl_eval("#{tree} set #{id} earned") }
|
|
183
|
+
assert_equal '', earned.last, "unearned must be last"
|
|
184
|
+
refute_equal '', earned.first, "earned must be first"
|
|
185
|
+
ensure
|
|
186
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def test_switching_sort_column_clears_old_indicator
|
|
192
|
+
assert_tk_app("switching sort column removes indicator from previously sorted column") do
|
|
193
|
+
begin
|
|
194
|
+
require "gemba/headless"
|
|
195
|
+
require "support/achievements_window_helpers"
|
|
196
|
+
Gemba.bus = Gemba::EventBus.new
|
|
197
|
+
|
|
198
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
199
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
200
|
+
backend.add_achievement(id: 'a', title: 'Alpha', description: '', points: 5) { false }
|
|
201
|
+
|
|
202
|
+
win = Gemba::AchievementsWindow.new(
|
|
203
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
204
|
+
)
|
|
205
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
206
|
+
win.show
|
|
207
|
+
win.refresh(backend)
|
|
208
|
+
app.update
|
|
209
|
+
|
|
210
|
+
tree = "#{Gemba::AchievementsWindow::TOP}.tf.tree"
|
|
211
|
+
name_cmd = app.tcl_eval("#{tree} heading name -command")
|
|
212
|
+
pts_cmd = app.tcl_eval("#{tree} heading points -command")
|
|
213
|
+
app.tcl_eval("uplevel #0 {#{name_cmd}}") # sort by name
|
|
214
|
+
app.tcl_eval("uplevel #0 {#{pts_cmd}}") # switch to points
|
|
215
|
+
app.update
|
|
216
|
+
|
|
217
|
+
name_text = app.tcl_eval("#{tree} heading name -text")
|
|
218
|
+
pts_text = app.tcl_eval("#{tree} heading points -text")
|
|
219
|
+
refute_includes name_text, '▲', "name heading must lose indicator after switching"
|
|
220
|
+
refute_includes name_text, '▼', "name heading must lose indicator after switching"
|
|
221
|
+
assert_includes pts_text, '▲', "points heading should show ▲"
|
|
222
|
+
ensure
|
|
223
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require_relative "../shared/tk_test_helper"
|
|
5
|
+
|
|
6
|
+
# Tests for AchievementsWindow treeview rendering — achievement rows, earned/
|
|
7
|
+
# unearned column display, and status bar earned count.
|
|
8
|
+
class TestAchievementsWindowTreeRendering < Minitest::Test
|
|
9
|
+
include TeekTestHelper
|
|
10
|
+
|
|
11
|
+
def test_tree_shows_achievement_titles
|
|
12
|
+
assert_tk_app("treeview rows show achievement titles from the backend") 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
|
+
backend.add_achievement(id: 'a1', title: 'First Act', description: '', points: 5) { false }
|
|
21
|
+
backend.add_achievement(id: 'a2', title: 'Second Act', description: '', points: 10) { false }
|
|
22
|
+
|
|
23
|
+
win = Gemba::AchievementsWindow.new(
|
|
24
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
25
|
+
)
|
|
26
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
27
|
+
win.show
|
|
28
|
+
win.refresh(backend)
|
|
29
|
+
app.update
|
|
30
|
+
|
|
31
|
+
tree = "#{Gemba::AchievementsWindow::TOP}.tf.tree"
|
|
32
|
+
items = app.tcl_eval("#{tree} children {}").split
|
|
33
|
+
titles = items.map { |id| app.tcl_eval("#{tree} set #{id} name") }
|
|
34
|
+
assert_equal 2, items.size
|
|
35
|
+
assert_includes titles, 'First Act'
|
|
36
|
+
assert_includes titles, 'Second Act'
|
|
37
|
+
ensure
|
|
38
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_unearned_achievements_have_empty_earned_column
|
|
44
|
+
assert_tk_app("unearned achievements show empty earned column") do
|
|
45
|
+
begin
|
|
46
|
+
require "gemba/headless"
|
|
47
|
+
require "support/achievements_window_helpers"
|
|
48
|
+
Gemba.bus = Gemba::EventBus.new
|
|
49
|
+
|
|
50
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
51
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
52
|
+
backend.add_achievement(id: 'a1', title: 'Unearned', description: '', points: 5) { false }
|
|
53
|
+
|
|
54
|
+
win = Gemba::AchievementsWindow.new(
|
|
55
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
56
|
+
)
|
|
57
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
58
|
+
win.show
|
|
59
|
+
win.refresh(backend)
|
|
60
|
+
app.update
|
|
61
|
+
|
|
62
|
+
tree = "#{Gemba::AchievementsWindow::TOP}.tf.tree"
|
|
63
|
+
item = app.tcl_eval("#{tree} children {}").split.first
|
|
64
|
+
assert_equal '', app.tcl_eval("#{tree} set #{item} earned")
|
|
65
|
+
ensure
|
|
66
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_earned_achievements_show_date
|
|
72
|
+
assert_tk_app("earned achievements show a YYYY-MM-DD date in the earned column") do
|
|
73
|
+
begin
|
|
74
|
+
require "gemba/headless"
|
|
75
|
+
require "support/achievements_window_helpers"
|
|
76
|
+
require "support/fake_core"
|
|
77
|
+
Gemba.bus = Gemba::EventBus.new
|
|
78
|
+
|
|
79
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
80
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
81
|
+
backend.add_achievement(id: 'a1', title: 'Earned One', description: '', points: 5) { |_| true }
|
|
82
|
+
backend.do_frame(FakeCore.new)
|
|
83
|
+
|
|
84
|
+
win = Gemba::AchievementsWindow.new(
|
|
85
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
86
|
+
)
|
|
87
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
88
|
+
win.show
|
|
89
|
+
win.refresh(backend)
|
|
90
|
+
app.update
|
|
91
|
+
|
|
92
|
+
tree = "#{Gemba::AchievementsWindow::TOP}.tf.tree"
|
|
93
|
+
item = app.tcl_eval("#{tree} children {}").split.first
|
|
94
|
+
earned = app.tcl_eval("#{tree} set #{item} earned")
|
|
95
|
+
assert_match(/\d{4}-\d{2}-\d{2}/, earned)
|
|
96
|
+
ensure
|
|
97
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def test_status_bar_shows_earned_count
|
|
103
|
+
assert_tk_app("status bar shows 'X / Y earned'") do
|
|
104
|
+
begin
|
|
105
|
+
require "gemba/headless"
|
|
106
|
+
require "support/achievements_window_helpers"
|
|
107
|
+
require "support/fake_core"
|
|
108
|
+
Gemba.bus = Gemba::EventBus.new
|
|
109
|
+
|
|
110
|
+
backend = Gemba::Achievements::FakeBackend.new
|
|
111
|
+
backend.login_with_token(username: 'u', token: 't')
|
|
112
|
+
backend.add_achievement(id: 'a1', title: 'Alpha', description: '', points: 5) { |_| true }
|
|
113
|
+
backend.add_achievement(id: 'a2', title: 'Beta', description: '', points: 5) { false }
|
|
114
|
+
backend.do_frame(FakeCore.new)
|
|
115
|
+
|
|
116
|
+
win = Gemba::AchievementsWindow.new(
|
|
117
|
+
app: app, rom_library: make_rom_library, config: FakeConfig.new(false)
|
|
118
|
+
)
|
|
119
|
+
win.update_game(rom_id: nil, backend: backend)
|
|
120
|
+
win.show
|
|
121
|
+
win.refresh(backend)
|
|
122
|
+
app.update
|
|
123
|
+
|
|
124
|
+
top = Gemba::AchievementsWindow::TOP
|
|
125
|
+
status = app.command("#{top}.status_bar.status", :cget, '-text').to_s
|
|
126
|
+
assert_includes status, '1'
|
|
127
|
+
assert_includes status, '2'
|
|
128
|
+
ensure
|
|
129
|
+
app.command(:destroy, Gemba::AchievementsWindow::TOP) rescue nil
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -67,7 +67,7 @@ class Teek::TestWorker
|
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
# Default timeout for test execution (can be overridden via TK_TEST_TIMEOUT env var)
|
|
70
|
-
DEFAULT_TIMEOUT =
|
|
70
|
+
DEFAULT_TIMEOUT = 10
|
|
71
71
|
|
|
72
72
|
def run_test(code, pipe_capture: false, timeout: nil, source_file: nil, source_line: nil)
|
|
73
73
|
start unless running?
|
|
@@ -171,6 +171,22 @@ class Teek::TestWorker
|
|
|
171
171
|
end
|
|
172
172
|
result
|
|
173
173
|
end
|
|
174
|
+
|
|
175
|
+
# Suppress tk_popup for the duration of the block so right-click bindings
|
|
176
|
+
# can build and configure menus without posting them. This avoids the
|
|
177
|
+
# platform grab that would block app.update on macOS and Windows.
|
|
178
|
+
#
|
|
179
|
+
# Uses Tcl `catch` so setup and teardown are idempotent — safe even if a
|
|
180
|
+
# previous test left _orig_tk_popup stranded due to an error.
|
|
181
|
+
def override_tk_popup
|
|
182
|
+
@app.tcl_eval("rename tk_popup _orig_tk_popup; proc tk_popup {args} {}")
|
|
183
|
+
yield
|
|
184
|
+
ensure
|
|
185
|
+
# Delete the no-op proc first (rename to {} = delete in Tcl), then
|
|
186
|
+
# restore the real tk_popup. Both wrapped in catch so a double-ensure
|
|
187
|
+
# or other edge case never raises.
|
|
188
|
+
@app.tcl_eval("catch {rename tk_popup {}}; catch {rename _orig_tk_popup tk_popup}")
|
|
189
|
+
end
|
|
174
190
|
end
|
|
175
191
|
|
|
176
192
|
# Server-side: runs in subprocess
|