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,152 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require "webmock"
|
|
5
|
+
require "gemba/headless"
|
|
6
|
+
|
|
7
|
+
RA_URL = "https://retroachievements.org/dorequest.php" unless defined?(RA_URL)
|
|
8
|
+
|
|
9
|
+
class TestCLISyncRequester < Minitest::Test
|
|
10
|
+
include WebMock::API
|
|
11
|
+
|
|
12
|
+
Requester = Gemba::Achievements::RetroAchievements::CliSyncRequester
|
|
13
|
+
|
|
14
|
+
def setup
|
|
15
|
+
WebMock.enable!
|
|
16
|
+
@req = Requester.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def teardown
|
|
20
|
+
WebMock.reset!
|
|
21
|
+
WebMock.disable!
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def stub_ra(body:, status: 200)
|
|
25
|
+
WebMock.stub_request(:post, RA_URL)
|
|
26
|
+
.to_return(status: status, body: body, headers: { "Content-Type" => "application/json" })
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# -- Result interface -------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
def test_result_on_progress_fires_synchronously
|
|
32
|
+
result = Requester::Result.new(["data", true])
|
|
33
|
+
received = nil
|
|
34
|
+
result.on_progress { |v| received = v }
|
|
35
|
+
assert_equal ["data", true], received
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_result_on_progress_returns_self_for_chaining
|
|
39
|
+
r = Requester::Result.new(nil)
|
|
40
|
+
assert_same r, r.on_progress {}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_result_on_done_returns_self
|
|
44
|
+
r = Requester::Result.new(nil)
|
|
45
|
+
assert_same r, r.on_done {}
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# -- Successful HTTP call ---------------------------------------------------
|
|
49
|
+
|
|
50
|
+
def test_success_returns_parsed_json_and_true
|
|
51
|
+
stub_ra(body: JSON.generate("Success" => true, "Token" => "abc"))
|
|
52
|
+
|
|
53
|
+
received = nil
|
|
54
|
+
@req.call(nil, { r: "login2", u: "user", p: "pass" })
|
|
55
|
+
.on_progress { |v| received = v }
|
|
56
|
+
|
|
57
|
+
assert_equal true, received[1]
|
|
58
|
+
assert_equal true, received[0]["Success"]
|
|
59
|
+
assert_equal "abc", received[0]["Token"]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def test_posts_to_correct_url
|
|
63
|
+
stub_ra(body: JSON.generate("Success" => true))
|
|
64
|
+
|
|
65
|
+
@req.call(nil, { r: "gameid", m: "deadbeef" })
|
|
66
|
+
.on_progress {}
|
|
67
|
+
|
|
68
|
+
assert_requested :post, RA_URL
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_sends_params_as_form_data
|
|
72
|
+
stub_ra(body: JSON.generate("GameID" => 42))
|
|
73
|
+
|
|
74
|
+
@req.call(nil, { r: "gameid", m: "abc123" })
|
|
75
|
+
.on_progress {}
|
|
76
|
+
|
|
77
|
+
assert_requested :post, RA_URL, body: "r=gameid&m=abc123"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def test_symbol_keys_stringified
|
|
81
|
+
stub_ra(body: JSON.generate("Success" => true))
|
|
82
|
+
|
|
83
|
+
@req.call(nil, { r: "ping", u: "user", t: "tok", g: 42, m: "Playing" })
|
|
84
|
+
.on_progress {}
|
|
85
|
+
|
|
86
|
+
assert_requested :post, RA_URL,
|
|
87
|
+
body: hash_including("r" => "ping", "u" => "user", "t" => "tok")
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# -- HTTP error responses ---------------------------------------------------
|
|
91
|
+
|
|
92
|
+
def test_http_404_returns_nil_false
|
|
93
|
+
stub_ra(body: "Not Found", status: 404)
|
|
94
|
+
|
|
95
|
+
received = nil
|
|
96
|
+
@req.call(nil, { r: "gameid", m: "bad" })
|
|
97
|
+
.on_progress { |v| received = v }
|
|
98
|
+
|
|
99
|
+
assert_equal [nil, false], received
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def test_http_500_returns_nil_false
|
|
103
|
+
stub_ra(body: "Internal Server Error", status: 500)
|
|
104
|
+
|
|
105
|
+
received = nil
|
|
106
|
+
@req.call(nil, { r: "patch", u: "u", t: "t", g: 1 })
|
|
107
|
+
.on_progress { |v| received = v }
|
|
108
|
+
|
|
109
|
+
assert_equal [nil, false], received
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# -- Network errors ---------------------------------------------------------
|
|
113
|
+
|
|
114
|
+
def test_connection_error_returns_nil_false
|
|
115
|
+
WebMock.stub_request(:post, RA_URL).to_raise(Errno::ECONNREFUSED)
|
|
116
|
+
|
|
117
|
+
received = nil
|
|
118
|
+
_, stderr = capture_io do
|
|
119
|
+
@req.call(nil, { r: "login2" }).on_progress { |v| received = v }
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
assert_equal [nil, false], received
|
|
123
|
+
assert_match(/request error/i, stderr)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def test_timeout_returns_nil_false
|
|
127
|
+
WebMock.stub_request(:post, RA_URL).to_raise(Net::ReadTimeout)
|
|
128
|
+
|
|
129
|
+
received = nil
|
|
130
|
+
capture_io do
|
|
131
|
+
@req.call(nil, { r: "login2" }).on_progress { |v| received = v }
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
assert_equal [nil, false], received
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# -- mode: and worker: kwargs are accepted but ignored ----------------------
|
|
138
|
+
|
|
139
|
+
def test_accepts_mode_kwarg
|
|
140
|
+
stub_ra(body: JSON.generate("ok" => true))
|
|
141
|
+
assert_silent do
|
|
142
|
+
@req.call(nil, { r: "ping" }, mode: :ractor).on_progress {}
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def test_accepts_worker_kwarg
|
|
147
|
+
stub_ra(body: JSON.generate("ok" => true))
|
|
148
|
+
assert_silent do
|
|
149
|
+
@req.call(nil, { r: "ping" }, worker: Object.new).on_progress {}
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require "gemba/headless"
|
|
5
|
+
require "gemba/cli/commands/version"
|
|
6
|
+
|
|
7
|
+
class TestCLIVersion < Minitest::Test
|
|
8
|
+
Version = Gemba::CLI::Commands::Version
|
|
9
|
+
|
|
10
|
+
def test_dry_run_returns_version
|
|
11
|
+
result = Version.new([], dry_run: true).call
|
|
12
|
+
assert_equal :version, result[:command]
|
|
13
|
+
assert_equal Gemba::VERSION, result[:version]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_prints_version
|
|
17
|
+
out = capture_io { Version.new([]).call }[0]
|
|
18
|
+
assert_includes out, "gemba"
|
|
19
|
+
assert_includes out, Gemba::VERSION
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_dry_run_via_dispatch
|
|
23
|
+
result = Gemba::CLI.run(["version"], dry_run: true)
|
|
24
|
+
assert_equal :version, result[:command]
|
|
25
|
+
assert_equal Gemba::VERSION, result[:version]
|
|
26
|
+
end
|
|
27
|
+
end
|
data/test/test_config.rb
CHANGED
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
require "minitest/autorun"
|
|
4
4
|
require "tmpdir"
|
|
5
5
|
require "json"
|
|
6
|
-
|
|
7
|
-
require_relative "../lib/gemba/version"
|
|
6
|
+
require "gemba/headless"
|
|
8
7
|
|
|
9
8
|
class TestMGBAConfig < Minitest::Test
|
|
10
9
|
def setup
|
|
@@ -747,7 +746,7 @@ class TestMGBAConfig < Minitest::Test
|
|
|
747
746
|
|
|
748
747
|
def test_per_game_settings_constant_keys
|
|
749
748
|
expected = %w[scale pixel_filter integer_scale color_correction frame_blending
|
|
750
|
-
volume muted turbo_speed quick_save_slot save_state_backup]
|
|
749
|
+
volume muted turbo_speed quick_save_slot save_state_backup ra_rich_presence]
|
|
751
750
|
assert_equal expected.sort, Gemba::Config::PER_GAME_SETTINGS.keys.sort
|
|
752
751
|
end
|
|
753
752
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require "tmpdir"
|
|
5
|
+
require "gemba/headless"
|
|
6
|
+
|
|
7
|
+
class TestConfigRA < Minitest::Test
|
|
8
|
+
def setup
|
|
9
|
+
@dir = Dir.mktmpdir("gemba-ra-test")
|
|
10
|
+
@path = File.join(@dir, "settings.json")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def teardown
|
|
14
|
+
FileUtils.rm_rf(@dir)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def new_config
|
|
18
|
+
Gemba::Config.new(path: @path)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_defaults
|
|
22
|
+
c = new_config
|
|
23
|
+
refute c.ra_enabled?
|
|
24
|
+
assert_equal '', c.ra_username
|
|
25
|
+
assert_equal '', c.ra_token
|
|
26
|
+
refute c.ra_hardcore?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_enabled_setter
|
|
30
|
+
c = new_config
|
|
31
|
+
c.ra_enabled = true
|
|
32
|
+
assert c.ra_enabled?
|
|
33
|
+
c.ra_enabled = false
|
|
34
|
+
refute c.ra_enabled?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_username_setter
|
|
38
|
+
c = new_config
|
|
39
|
+
c.ra_username = 'alice'
|
|
40
|
+
assert_equal 'alice', c.ra_username
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_token_setter
|
|
44
|
+
c = new_config
|
|
45
|
+
c.ra_token = 'abc123'
|
|
46
|
+
assert_equal 'abc123', c.ra_token
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def test_hardcore_setter
|
|
50
|
+
c = new_config
|
|
51
|
+
c.ra_hardcore = true
|
|
52
|
+
assert c.ra_hardcore?
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def test_persistence_roundtrip
|
|
56
|
+
c = new_config
|
|
57
|
+
c.ra_enabled = true
|
|
58
|
+
c.ra_username = 'alice'
|
|
59
|
+
c.ra_token = 'secret'
|
|
60
|
+
c.ra_hardcore = true
|
|
61
|
+
c.save!
|
|
62
|
+
|
|
63
|
+
c2 = new_config
|
|
64
|
+
assert c2.ra_enabled?
|
|
65
|
+
assert_equal 'alice', c2.ra_username
|
|
66
|
+
assert_equal 'secret', c2.ra_token
|
|
67
|
+
assert c2.ra_hardcore?
|
|
68
|
+
end
|
|
69
|
+
end
|
data/test/test_core.rb
CHANGED
|
@@ -10,7 +10,6 @@ class TestMGBACore < Minitest::Test
|
|
|
10
10
|
TEST_ROM = File.expand_path("fixtures/test.gba", __dir__)
|
|
11
11
|
|
|
12
12
|
def setup
|
|
13
|
-
skip "Run: ruby gemba/scripts/generate_test_rom.rb" unless File.exist?(TEST_ROM)
|
|
14
13
|
@core = Gemba::Core.new(TEST_ROM)
|
|
15
14
|
end
|
|
16
15
|
|
|
@@ -385,6 +384,68 @@ class TestMGBACore < Minitest::Test
|
|
|
385
384
|
assert_raises(ArgumentError) { @core.rewind_init(-1) }
|
|
386
385
|
end
|
|
387
386
|
|
|
387
|
+
# -- GB / GBC ROM loading ----------------------------------------------------
|
|
388
|
+
|
|
389
|
+
GB_ROM = File.expand_path("fixtures/test.gb", __dir__)
|
|
390
|
+
GBC_ROM = File.expand_path("fixtures/test.gbc", __dir__)
|
|
391
|
+
|
|
392
|
+
def test_gb_rom_dimensions
|
|
393
|
+
core = Gemba::Core.new(GB_ROM)
|
|
394
|
+
assert_equal 160, core.width
|
|
395
|
+
assert_equal 144, core.height
|
|
396
|
+
assert_equal "GB", core.platform
|
|
397
|
+
core.destroy
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
def test_gb_rom_video_buffer_size
|
|
401
|
+
core = Gemba::Core.new(GB_ROM)
|
|
402
|
+
core.run_frame
|
|
403
|
+
buf = core.video_buffer_argb
|
|
404
|
+
assert_equal 160 * 144 * 4, buf.bytesize
|
|
405
|
+
core.destroy
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
def test_gb_rom_title
|
|
409
|
+
core = Gemba::Core.new(GB_ROM)
|
|
410
|
+
assert_equal "GEMBAGB", core.title
|
|
411
|
+
core.destroy
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
def test_gb_rom_runs_frames
|
|
415
|
+
core = Gemba::Core.new(GB_ROM)
|
|
416
|
+
10.times { core.run_frame }
|
|
417
|
+
assert_equal 160 * 144 * 4, core.video_buffer.bytesize
|
|
418
|
+
core.destroy
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
def test_gbc_rom_dimensions
|
|
422
|
+
core = Gemba::Core.new(GBC_ROM)
|
|
423
|
+
assert_equal 160, core.width
|
|
424
|
+
assert_equal 144, core.height
|
|
425
|
+
core.destroy
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
def test_gbc_rom_video_buffer_size
|
|
429
|
+
core = Gemba::Core.new(GBC_ROM)
|
|
430
|
+
core.run_frame
|
|
431
|
+
buf = core.video_buffer_argb
|
|
432
|
+
assert_equal 160 * 144 * 4, buf.bytesize
|
|
433
|
+
core.destroy
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
def test_gbc_rom_title
|
|
437
|
+
core = Gemba::Core.new(GBC_ROM)
|
|
438
|
+
assert_equal "GEMBAGBC", core.title
|
|
439
|
+
core.destroy
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
def test_gbc_rom_runs_frames
|
|
443
|
+
core = Gemba::Core.new(GBC_ROM)
|
|
444
|
+
10.times { core.run_frame }
|
|
445
|
+
assert_equal 160 * 144 * 4, core.video_buffer.bytesize
|
|
446
|
+
core.destroy
|
|
447
|
+
end
|
|
448
|
+
|
|
388
449
|
# -- Error handling ----------------------------------------------------------
|
|
389
450
|
|
|
390
451
|
def test_nonexistent_file
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require "gemba/headless"
|
|
5
|
+
|
|
6
|
+
class TestCredentialsPresenter < Minitest::Test
|
|
7
|
+
def setup
|
|
8
|
+
Gemba.bus = Gemba::EventBus.new
|
|
9
|
+
@config = Gemba::Config.new(path: nil) # in-memory defaults
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def presenter(**overrides)
|
|
13
|
+
cfg = @config
|
|
14
|
+
cfg.ra_enabled = overrides.fetch(:enabled, false)
|
|
15
|
+
cfg.ra_username = overrides.fetch(:username, '')
|
|
16
|
+
cfg.ra_token = overrides.fetch(:token, '')
|
|
17
|
+
Gemba::Achievements::CredentialsPresenter.new(cfg)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# -- Disabled state ----------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
def test_disabled_everything_off
|
|
23
|
+
p = presenter(enabled: false)
|
|
24
|
+
assert_equal :disabled, p.fields_state
|
|
25
|
+
assert_equal :disabled, p.login_button_state
|
|
26
|
+
assert_equal :disabled, p.verify_button_state
|
|
27
|
+
assert_equal :disabled, p.logout_button_state
|
|
28
|
+
assert_equal :disabled, p.reset_button_state
|
|
29
|
+
assert_equal :empty, p.feedback[:key]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# -- Enabled, not logged in --------------------------------------------------
|
|
33
|
+
|
|
34
|
+
def test_enabled_no_token_fields_editable
|
|
35
|
+
p = presenter(enabled: true)
|
|
36
|
+
assert_equal :normal, p.fields_state
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_enabled_no_token_login_disabled_when_fields_empty
|
|
40
|
+
p = presenter(enabled: true)
|
|
41
|
+
assert_equal :disabled, p.login_button_state
|
|
42
|
+
assert_equal :disabled, p.verify_button_state
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def test_enabled_login_enabled_when_fields_filled
|
|
46
|
+
p = presenter(enabled: true)
|
|
47
|
+
p.username = 'alice'
|
|
48
|
+
p.password = 'secret'
|
|
49
|
+
assert_equal :normal, p.login_button_state
|
|
50
|
+
assert_equal :disabled, p.verify_button_state # no token yet — verify stays disabled
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def test_enabled_login_disabled_with_only_username
|
|
54
|
+
p = presenter(enabled: true)
|
|
55
|
+
p.username = 'alice'
|
|
56
|
+
assert_equal :disabled, p.login_button_state
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def test_enabled_login_disabled_with_only_password
|
|
60
|
+
p = presenter(enabled: true)
|
|
61
|
+
p.password = 'secret'
|
|
62
|
+
assert_equal :disabled, p.login_button_state
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_enabled_no_token_logout_and_reset_disabled
|
|
66
|
+
p = presenter(enabled: true)
|
|
67
|
+
assert_equal :disabled, p.logout_button_state
|
|
68
|
+
assert_equal :disabled, p.reset_button_state
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_enabled_no_token_feedback_not_logged_in
|
|
72
|
+
p = presenter(enabled: true)
|
|
73
|
+
assert_equal :not_logged_in, p.feedback[:key]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# -- Enabled, logged in (token present) --------------------------------------
|
|
77
|
+
|
|
78
|
+
def test_logged_in_fields_disabled
|
|
79
|
+
p = presenter(enabled: true, username: 'alice', token: 'tok123')
|
|
80
|
+
assert_equal :readonly, p.fields_state
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def test_logged_in_login_disabled
|
|
84
|
+
p = presenter(enabled: true, username: 'alice', token: 'tok123')
|
|
85
|
+
assert_equal :disabled, p.login_button_state
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def test_logged_in_verify_enabled
|
|
89
|
+
p = presenter(enabled: true, username: 'alice', token: 'tok123')
|
|
90
|
+
assert_equal :normal, p.verify_button_state
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def test_logged_in_logout_and_reset_enabled
|
|
94
|
+
p = presenter(enabled: true, username: 'alice', token: 'tok123')
|
|
95
|
+
assert_equal :normal, p.logout_button_state
|
|
96
|
+
assert_equal :normal, p.reset_button_state
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def test_logged_in_feedback_shows_username
|
|
100
|
+
p = presenter(enabled: true, username: 'alice', token: 'tok123')
|
|
101
|
+
fb = p.feedback
|
|
102
|
+
assert_equal :logged_in_as, fb[:key]
|
|
103
|
+
assert_equal 'alice', fb[:username]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# -- State mutations ----------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
def test_enabling_clears_disabled_state
|
|
109
|
+
p = presenter(enabled: false)
|
|
110
|
+
assert_equal :disabled, p.fields_state
|
|
111
|
+
p.enabled = true
|
|
112
|
+
assert_equal :normal, p.fields_state
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def test_credentials_changed_emitted_on_mutations
|
|
116
|
+
p = presenter(enabled: false)
|
|
117
|
+
fired = 0
|
|
118
|
+
Gemba.bus.on(:credentials_changed) { fired += 1 }
|
|
119
|
+
p.enabled = true
|
|
120
|
+
p.username = 'alice'
|
|
121
|
+
p.password = 'pw'
|
|
122
|
+
assert_equal 3, fired
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# -- Auth result handling (via :ra_auth_result bus events) -------------------
|
|
126
|
+
|
|
127
|
+
def auth(status, token: nil, message: nil)
|
|
128
|
+
Gemba.bus.emit(:ra_auth_result, status: status, token: token, message: message)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def test_login_success_stores_token_and_clears_password
|
|
132
|
+
p = presenter(enabled: true, username: 'alice')
|
|
133
|
+
p.password = 'pw'
|
|
134
|
+
auth(:ok, token: 'real_token')
|
|
135
|
+
assert_equal 'real_token', p.token
|
|
136
|
+
assert_equal '', p.password
|
|
137
|
+
assert p.logged_in?
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def test_login_success_locks_fields
|
|
141
|
+
p = presenter(enabled: true, username: 'alice')
|
|
142
|
+
auth(:ok, token: 'tok')
|
|
143
|
+
assert_equal :readonly, p.fields_state
|
|
144
|
+
assert_equal :normal, p.logout_button_state
|
|
145
|
+
assert_equal :normal, p.verify_button_state
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def test_login_error_sets_feedback
|
|
149
|
+
p = presenter(enabled: true, username: 'alice')
|
|
150
|
+
auth(:error, message: 'Bad credentials')
|
|
151
|
+
assert_equal :error, p.feedback[:key]
|
|
152
|
+
assert_equal 'Bad credentials', p.feedback[:message]
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def test_login_error_does_not_affect_button_states
|
|
156
|
+
p = presenter(enabled: true, username: 'alice')
|
|
157
|
+
p.password = 'pw'
|
|
158
|
+
auth(:error, message: 'Bad credentials')
|
|
159
|
+
# Fields and login button should still be enabled
|
|
160
|
+
assert_equal :normal, p.fields_state
|
|
161
|
+
assert_equal :normal, p.login_button_state
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def test_logout_clears_token_keeps_username
|
|
165
|
+
p = presenter(enabled: true, username: 'alice', token: 'tok')
|
|
166
|
+
auth(:logout)
|
|
167
|
+
assert_equal '', p.token
|
|
168
|
+
assert_equal 'alice', p.username # kept so user can re-enter password
|
|
169
|
+
refute p.logged_in?
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def test_logout_re_enables_fields
|
|
173
|
+
p = presenter(enabled: true, username: 'alice', token: 'tok')
|
|
174
|
+
auth(:logout)
|
|
175
|
+
assert_equal :normal, p.fields_state
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# -- Transient feedback -------------------------------------------------------
|
|
179
|
+
|
|
180
|
+
def test_transient_overrides_normal_feedback
|
|
181
|
+
p = presenter(enabled: true, username: 'alice', token: 'tok')
|
|
182
|
+
p.show_transient(:test_ok)
|
|
183
|
+
assert_equal :test_ok, p.feedback[:key]
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def test_clear_transient_restores_normal_feedback
|
|
187
|
+
p = presenter(enabled: true, username: 'alice', token: 'tok')
|
|
188
|
+
p.show_transient(:test_ok)
|
|
189
|
+
p.clear_transient
|
|
190
|
+
assert_equal :logged_in_as, p.feedback[:key]
|
|
191
|
+
end
|
|
192
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require "gemba/headless"
|
|
5
|
+
|
|
6
|
+
class TestEventBus < Minitest::Test
|
|
7
|
+
def setup
|
|
8
|
+
@bus = Gemba::EventBus.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def test_on_and_emit
|
|
12
|
+
received = nil
|
|
13
|
+
@bus.on(:ping) { |val| received = val }
|
|
14
|
+
@bus.emit(:ping, 42)
|
|
15
|
+
assert_equal 42, received
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_emit_with_no_subscribers_is_noop
|
|
19
|
+
@bus.emit(:ghost, 1, 2, 3) # should not raise
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_multiple_subscribers
|
|
23
|
+
results = []
|
|
24
|
+
@bus.on(:tick) { |v| results << "a:#{v}" }
|
|
25
|
+
@bus.on(:tick) { |v| results << "b:#{v}" }
|
|
26
|
+
@bus.emit(:tick, 7)
|
|
27
|
+
assert_equal ["a:7", "b:7"], results
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_different_events_are_independent
|
|
31
|
+
a = nil
|
|
32
|
+
b = nil
|
|
33
|
+
@bus.on(:foo) { |v| a = v }
|
|
34
|
+
@bus.on(:bar) { |v| b = v }
|
|
35
|
+
@bus.emit(:foo, 1)
|
|
36
|
+
assert_equal 1, a
|
|
37
|
+
assert_nil b
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_emit_multiple_args
|
|
41
|
+
received = nil
|
|
42
|
+
@bus.on(:multi) { |x, y| received = [x, y] }
|
|
43
|
+
@bus.emit(:multi, :a, :b)
|
|
44
|
+
assert_equal [:a, :b], received
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_emit_with_kwargs
|
|
48
|
+
received = nil
|
|
49
|
+
@bus.on(:kw) { |name:, val:| received = { name: name, val: val } }
|
|
50
|
+
@bus.emit(:kw, name: "scale", val: 3)
|
|
51
|
+
assert_equal({ name: "scale", val: 3 }, received)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_off_removes_subscriber
|
|
55
|
+
received = []
|
|
56
|
+
block = @bus.on(:evt) { |v| received << v }
|
|
57
|
+
@bus.emit(:evt, 1)
|
|
58
|
+
@bus.off(:evt, block)
|
|
59
|
+
@bus.emit(:evt, 2)
|
|
60
|
+
assert_equal [1], received
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_on_returns_block_for_later_off
|
|
64
|
+
block = @bus.on(:x) { }
|
|
65
|
+
assert_instance_of Proc, block
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# -- Module-level accessor ------------------------------------------------
|
|
69
|
+
|
|
70
|
+
def test_gemba_bus_auto_creates
|
|
71
|
+
Gemba.bus = nil
|
|
72
|
+
bus = Gemba.bus
|
|
73
|
+
assert_instance_of Gemba::EventBus, bus
|
|
74
|
+
ensure
|
|
75
|
+
Gemba.bus = nil
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_gemba_bus_setter
|
|
79
|
+
custom = Gemba::EventBus.new
|
|
80
|
+
Gemba.bus = custom
|
|
81
|
+
assert_same custom, Gemba.bus
|
|
82
|
+
ensure
|
|
83
|
+
Gemba.bus = nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# -- BusEmitter mixin -----------------------------------------------------
|
|
87
|
+
|
|
88
|
+
def test_bus_emitter_emits_to_gemba_bus
|
|
89
|
+
Gemba.bus = @bus
|
|
90
|
+
klass = Class.new { include Gemba::BusEmitter; public :emit }
|
|
91
|
+
obj = klass.new
|
|
92
|
+
|
|
93
|
+
received = nil
|
|
94
|
+
@bus.on(:test_event) { |v| received = v }
|
|
95
|
+
obj.emit(:test_event, 99)
|
|
96
|
+
assert_equal 99, received
|
|
97
|
+
ensure
|
|
98
|
+
Gemba.bus = nil
|
|
99
|
+
end
|
|
100
|
+
end
|