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,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require "tmpdir"
|
|
5
|
+
require "fileutils"
|
|
6
|
+
require "gemba/headless"
|
|
7
|
+
|
|
8
|
+
class TestLogging < Minitest::Test
|
|
9
|
+
def setup
|
|
10
|
+
@dir = Dir.mktmpdir("gemba-logs-test")
|
|
11
|
+
@logger = Gemba::SessionLogger.new(dir: @dir, level: :info)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def teardown
|
|
15
|
+
Gemba.logger = nil
|
|
16
|
+
FileUtils.rm_rf(@dir)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# -- lazy file creation --
|
|
20
|
+
|
|
21
|
+
def test_no_file_before_first_log
|
|
22
|
+
assert_empty Dir.glob(File.join(@dir, "*.log"))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_file_created_on_first_log
|
|
26
|
+
@logger.log(:info) { "hello" }
|
|
27
|
+
logs = Dir.glob(File.join(@dir, "*.log"))
|
|
28
|
+
assert_equal 1, logs.length
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_file_named_by_date
|
|
32
|
+
@logger.log(:info) { "hello" }
|
|
33
|
+
logs = Dir.glob(File.join(@dir, "*.log"))
|
|
34
|
+
assert_match(/gemba-\d{4}-\d{2}-\d{2}\.log/, File.basename(logs.first))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# -- level filtering --
|
|
38
|
+
|
|
39
|
+
def test_filters_below_level
|
|
40
|
+
@logger.log(:debug) { "should not appear" }
|
|
41
|
+
assert_empty Dir.glob(File.join(@dir, "*.log")),
|
|
42
|
+
"Debug message should not create log file at info level"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def test_allows_at_level
|
|
46
|
+
@logger.log(:info) { "visible" }
|
|
47
|
+
content = File.read(Dir.glob(File.join(@dir, "*.log")).first)
|
|
48
|
+
assert_includes content, "visible"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def test_allows_above_level
|
|
52
|
+
@logger.log(:error) { "bad thing" }
|
|
53
|
+
content = File.read(Dir.glob(File.join(@dir, "*.log")).first)
|
|
54
|
+
assert_includes content, "bad thing"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def test_debug_level_allows_debug
|
|
58
|
+
logger = Gemba::SessionLogger.new(dir: @dir, level: :debug)
|
|
59
|
+
logger.log(:debug) { "debug msg" }
|
|
60
|
+
content = File.read(Dir.glob(File.join(@dir, "*.log")).first)
|
|
61
|
+
assert_includes content, "debug msg"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# -- log format --
|
|
65
|
+
|
|
66
|
+
def test_log_format
|
|
67
|
+
@logger.log(:info) { "test message" }
|
|
68
|
+
content = File.read(Dir.glob(File.join(@dir, "*.log")).first)
|
|
69
|
+
assert_match(/\d{2}:\d{2}:\d{2}\.\d{3} \[INFO\] test message/, content)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# -- auto-prune --
|
|
73
|
+
|
|
74
|
+
def test_prune_keeps_max_files
|
|
75
|
+
# Create 30 fake log files
|
|
76
|
+
30.times do |i|
|
|
77
|
+
File.write(File.join(@dir, "gemba-2026-01-#{format('%02d', i + 1)}.log"), "old")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# New logger prunes on init
|
|
81
|
+
Gemba::SessionLogger.new(dir: @dir, level: :info)
|
|
82
|
+
|
|
83
|
+
remaining = Dir.glob(File.join(@dir, "gemba-*.log"))
|
|
84
|
+
assert_equal Gemba::SessionLogger::MAX_LOG_FILES, remaining.length
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def test_prune_keeps_newest
|
|
88
|
+
30.times do |i|
|
|
89
|
+
File.write(File.join(@dir, "gemba-2026-01-#{format('%02d', i + 1)}.log"), "old")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
Gemba::SessionLogger.new(dir: @dir, level: :info)
|
|
93
|
+
|
|
94
|
+
remaining = Dir.glob(File.join(@dir, "gemba-*.log")).sort
|
|
95
|
+
# Should keep the last 25 (days 06-30)
|
|
96
|
+
assert_equal "gemba-2026-01-06.log", File.basename(remaining.first)
|
|
97
|
+
assert_equal "gemba-2026-01-30.log", File.basename(remaining.last)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def test_prune_no_op_when_under_limit
|
|
101
|
+
3.times do |i|
|
|
102
|
+
File.write(File.join(@dir, "gemba-2026-01-#{format('%02d', i + 1)}.log"), "ok")
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
Gemba::SessionLogger.new(dir: @dir, level: :info)
|
|
106
|
+
assert_equal 3, Dir.glob(File.join(@dir, "gemba-*.log")).length
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# -- module interface --
|
|
110
|
+
|
|
111
|
+
def test_gemba_log_module_method
|
|
112
|
+
Gemba.logger = Gemba::SessionLogger.new(dir: @dir, level: :info)
|
|
113
|
+
Gemba.log(:info) { "module test" }
|
|
114
|
+
content = File.read(Dir.glob(File.join(@dir, "*.log")).first)
|
|
115
|
+
assert_includes content, "module test"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def test_gemba_logger_setter
|
|
119
|
+
custom = Gemba::SessionLogger.new(dir: @dir, level: :warn)
|
|
120
|
+
Gemba.logger = custom
|
|
121
|
+
assert_same custom, Gemba.logger
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require "gemba/headless"
|
|
5
|
+
require "gemba/achievements"
|
|
6
|
+
require_relative "support/fake_core"
|
|
7
|
+
|
|
8
|
+
class TestNullBackend < Minitest::Test
|
|
9
|
+
def setup
|
|
10
|
+
@b = Gemba::Achievements::NullBackend.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_not_enabled
|
|
14
|
+
refute @b.enabled?
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_not_authenticated
|
|
18
|
+
refute @b.authenticated?
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_achievement_list_empty
|
|
22
|
+
assert_equal [], @b.achievement_list
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_counts_zero
|
|
26
|
+
assert_equal 0, @b.earned_count
|
|
27
|
+
assert_equal 0, @b.total_count
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_do_frame_is_noop
|
|
31
|
+
assert_nil @b.do_frame(FakeCore.new)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def test_login_noop
|
|
35
|
+
assert_nil @b.login_with_token(username: 'u', token: 't')
|
|
36
|
+
refute @b.authenticated?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_logout_noop
|
|
40
|
+
assert_nil @b.logout
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require "gemba/headless"
|
|
5
|
+
|
|
6
|
+
class TestOfflineBackend < Minitest::Test
|
|
7
|
+
ROM = "test/fixtures/test.gba"
|
|
8
|
+
|
|
9
|
+
def setup
|
|
10
|
+
skip "test.gba fixture not found" unless File.exist?(ROM)
|
|
11
|
+
@unlocked = []
|
|
12
|
+
@backend = Gemba::Achievements::OfflineBackend.new
|
|
13
|
+
@backend.on_unlock { |ach| @unlocked << ach }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_always_authenticated
|
|
17
|
+
assert @backend.authenticated?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_enabled
|
|
21
|
+
assert @backend.enabled?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_login_and_logout_are_noops
|
|
25
|
+
@backend.login_with_password(username: "anyone", password: "anything")
|
|
26
|
+
assert @backend.authenticated?
|
|
27
|
+
@backend.logout
|
|
28
|
+
assert @backend.authenticated?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_on_load_achievement_fires_during_load_game
|
|
32
|
+
Gemba::HeadlessPlayer.open(ROM) do |player|
|
|
33
|
+
@backend.load_game(player.core)
|
|
34
|
+
assert_equal 1, @unlocked.size
|
|
35
|
+
assert_equal "gembatest_loaded", @unlocked.first.id
|
|
36
|
+
assert_equal "Ready to Play", @unlocked.first.title
|
|
37
|
+
assert @unlocked.first.earned?
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_achievement_list_shows_earned_after_load
|
|
42
|
+
Gemba::HeadlessPlayer.open(ROM) do |player|
|
|
43
|
+
@backend.load_game(player.core)
|
|
44
|
+
list = @backend.achievement_list
|
|
45
|
+
assert_equal 1, list.size
|
|
46
|
+
assert list.first.earned?
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def test_counts
|
|
51
|
+
Gemba::HeadlessPlayer.open(ROM) do |player|
|
|
52
|
+
assert_equal 0, @backend.total_count
|
|
53
|
+
@backend.load_game(player.core)
|
|
54
|
+
assert_equal 1, @backend.total_count
|
|
55
|
+
assert_equal 1, @backend.earned_count
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def test_unload_game_clears_state
|
|
60
|
+
Gemba::HeadlessPlayer.open(ROM) do |player|
|
|
61
|
+
@backend.load_game(player.core)
|
|
62
|
+
assert_equal 1, @backend.earned_count
|
|
63
|
+
@backend.unload_game
|
|
64
|
+
assert_equal 0, @backend.total_count
|
|
65
|
+
assert_equal 0, @backend.earned_count
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_unknown_rom_has_no_achievements
|
|
70
|
+
Gemba::HeadlessPlayer.open(ROM) do |player|
|
|
71
|
+
custom = Gemba::Achievements::OfflineBackend.new(db: {})
|
|
72
|
+
custom.load_game(player.core)
|
|
73
|
+
assert_equal 0, custom.total_count
|
|
74
|
+
assert_empty @unlocked
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_store_adds_definitions
|
|
79
|
+
Gemba::HeadlessPlayer.open(ROM) do |player|
|
|
80
|
+
custom = Gemba::Achievements::OfflineBackend.new(db: {})
|
|
81
|
+
custom.on_unlock { |a| @unlocked << a }
|
|
82
|
+
custom.store(player.core.checksum, [
|
|
83
|
+
{ id: "extra", title: "Extra", description: "desc",
|
|
84
|
+
points: 5, trigger: :on_load }
|
|
85
|
+
])
|
|
86
|
+
custom.load_game(player.core)
|
|
87
|
+
assert_equal 1, @unlocked.size
|
|
88
|
+
assert_equal "extra", @unlocked.first.id
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def test_memory_achievement_fires_on_rising_edge
|
|
93
|
+
addr = 0x02000000
|
|
94
|
+
Gemba::HeadlessPlayer.open(ROM) do |player|
|
|
95
|
+
backend = Gemba::Achievements::OfflineBackend.new(db: {
|
|
96
|
+
player.core.checksum => [
|
|
97
|
+
{ id: "mem_test", title: "Mem", description: "d", points: 2,
|
|
98
|
+
trigger: :memory,
|
|
99
|
+
condition: ->(mem) { mem.call(addr) == 0x01 } }
|
|
100
|
+
]
|
|
101
|
+
})
|
|
102
|
+
backend.on_unlock { |a| @unlocked << a }
|
|
103
|
+
backend.load_game(player.core)
|
|
104
|
+
|
|
105
|
+
# EWRAM starts zeroed — condition false
|
|
106
|
+
player.step(1)
|
|
107
|
+
backend.do_frame(player.core)
|
|
108
|
+
assert_empty @unlocked
|
|
109
|
+
|
|
110
|
+
# Write 0x01 to EWRAM — but we can't poke real memory from Ruby,
|
|
111
|
+
# so verify do_frame doesn't crash and condition stays unevaluated
|
|
112
|
+
backend.do_frame(player.core)
|
|
113
|
+
assert_empty @unlocked
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "minitest/autorun"
|
|
4
|
+
require "gemba/headless"
|
|
5
|
+
|
|
6
|
+
class TestPlatform < Minitest::Test
|
|
7
|
+
# -- Factory ---------------------------------------------------------------
|
|
8
|
+
|
|
9
|
+
def test_for_gba
|
|
10
|
+
core = MockCore.new("GBA")
|
|
11
|
+
platform = Gemba::Platform.for(core)
|
|
12
|
+
assert_instance_of Gemba::Platform::GBA, platform
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def test_for_gb
|
|
16
|
+
core = MockCore.new("GB")
|
|
17
|
+
platform = Gemba::Platform.for(core)
|
|
18
|
+
assert_instance_of Gemba::Platform::GB, platform
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_for_gbc
|
|
22
|
+
core = MockCore.new("GBC")
|
|
23
|
+
platform = Gemba::Platform.for(core)
|
|
24
|
+
assert_instance_of Gemba::Platform::GBC, platform
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def test_for_unknown_defaults_to_gb
|
|
28
|
+
core = MockCore.new("Unknown")
|
|
29
|
+
platform = Gemba::Platform.for(core)
|
|
30
|
+
assert_instance_of Gemba::Platform::GB, platform
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_default_is_gba
|
|
34
|
+
platform = Gemba::Platform.default
|
|
35
|
+
assert_instance_of Gemba::Platform::GBA, platform
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# -- GBA -------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
def test_gba_resolution
|
|
41
|
+
p = Gemba::Platform::GBA.new
|
|
42
|
+
assert_equal 240, p.width
|
|
43
|
+
assert_equal 160, p.height
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_gba_fps
|
|
47
|
+
p = Gemba::Platform::GBA.new
|
|
48
|
+
assert_in_delta 59.7272, p.fps, 0.001
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def test_gba_fps_fraction
|
|
52
|
+
num, den = Gemba::Platform::GBA.new.fps_fraction
|
|
53
|
+
assert_in_delta 59.7272, num.to_f / den, 0.001
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_gba_aspect
|
|
57
|
+
assert_equal [3, 2], Gemba::Platform::GBA.new.aspect
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_gba_name
|
|
61
|
+
assert_equal "Game Boy Advance", Gemba::Platform::GBA.new.name
|
|
62
|
+
assert_equal "GBA", Gemba::Platform::GBA.new.short_name
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_gba_buttons_include_lr
|
|
66
|
+
buttons = Gemba::Platform::GBA.new.buttons
|
|
67
|
+
assert_includes buttons, :l
|
|
68
|
+
assert_includes buttons, :r
|
|
69
|
+
assert_equal 10, buttons.size
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_gba_thumb_size
|
|
73
|
+
assert_equal [120, 80], Gemba::Platform::GBA.new.thumb_size
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# -- GB --------------------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
def test_gb_resolution
|
|
79
|
+
p = Gemba::Platform::GB.new
|
|
80
|
+
assert_equal 160, p.width
|
|
81
|
+
assert_equal 144, p.height
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def test_gb_fps
|
|
85
|
+
assert_in_delta 59.7275, Gemba::Platform::GB.new.fps, 0.001
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def test_gb_fps_fraction
|
|
89
|
+
num, den = Gemba::Platform::GB.new.fps_fraction
|
|
90
|
+
assert_in_delta 59.7275, num.to_f / den, 0.001
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def test_gb_aspect
|
|
94
|
+
assert_equal [10, 9], Gemba::Platform::GB.new.aspect
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def test_gb_name
|
|
98
|
+
assert_equal "Game Boy", Gemba::Platform::GB.new.name
|
|
99
|
+
assert_equal "GB", Gemba::Platform::GB.new.short_name
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def test_gb_buttons_no_lr
|
|
103
|
+
buttons = Gemba::Platform::GB.new.buttons
|
|
104
|
+
refute_includes buttons, :l
|
|
105
|
+
refute_includes buttons, :r
|
|
106
|
+
assert_equal 8, buttons.size
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def test_gb_thumb_size
|
|
110
|
+
assert_equal [80, 72], Gemba::Platform::GB.new.thumb_size
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# -- GBC -------------------------------------------------------------------
|
|
114
|
+
|
|
115
|
+
def test_gbc_resolution_same_as_gb
|
|
116
|
+
p = Gemba::Platform::GBC.new
|
|
117
|
+
assert_equal 160, p.width
|
|
118
|
+
assert_equal 144, p.height
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def test_gbc_name_differs_from_gb
|
|
122
|
+
assert_equal "Game Boy Color", Gemba::Platform::GBC.new.name
|
|
123
|
+
assert_equal "GBC", Gemba::Platform::GBC.new.short_name
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def test_gbc_buttons_no_lr
|
|
127
|
+
buttons = Gemba::Platform::GBC.new.buttons
|
|
128
|
+
refute_includes buttons, :l
|
|
129
|
+
refute_includes buttons, :r
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# -- Equality --------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
def test_same_platform_equal
|
|
135
|
+
assert_equal Gemba::Platform::GBA.new, Gemba::Platform::GBA.new
|
|
136
|
+
assert_equal Gemba::Platform::GB.new, Gemba::Platform::GB.new
|
|
137
|
+
assert_equal Gemba::Platform::GBC.new, Gemba::Platform::GBC.new
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def test_different_platforms_not_equal
|
|
141
|
+
refute_equal Gemba::Platform::GBA.new, Gemba::Platform::GB.new
|
|
142
|
+
refute_equal Gemba::Platform::GBA.new, Gemba::Platform::GBC.new
|
|
143
|
+
refute_equal Gemba::Platform::GB.new, Gemba::Platform::GBC.new
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
private
|
|
147
|
+
|
|
148
|
+
MockCore = Struct.new(:platform)
|
|
149
|
+
end
|