gemba 0.1.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.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/THIRD_PARTY_NOTICES +113 -0
  3. data/assets/JetBrainsMonoNL-Regular.ttf +0 -0
  4. data/assets/ark-pixel-12px-monospaced-ja.ttf +0 -0
  5. data/bin/gemba +14 -0
  6. data/ext/gemba/extconf.rb +185 -0
  7. data/ext/gemba/gemba_ext.c +1051 -0
  8. data/ext/gemba/gemba_ext.h +15 -0
  9. data/gemba.gemspec +38 -0
  10. data/lib/gemba/child_window.rb +62 -0
  11. data/lib/gemba/cli.rb +384 -0
  12. data/lib/gemba/config.rb +621 -0
  13. data/lib/gemba/core.rb +121 -0
  14. data/lib/gemba/headless.rb +12 -0
  15. data/lib/gemba/headless_player.rb +206 -0
  16. data/lib/gemba/hotkey_map.rb +202 -0
  17. data/lib/gemba/input_mappings.rb +214 -0
  18. data/lib/gemba/locale.rb +92 -0
  19. data/lib/gemba/locales/en.yml +157 -0
  20. data/lib/gemba/locales/ja.yml +157 -0
  21. data/lib/gemba/method_coverage_service.rb +265 -0
  22. data/lib/gemba/overlay_renderer.rb +109 -0
  23. data/lib/gemba/player.rb +1515 -0
  24. data/lib/gemba/recorder.rb +156 -0
  25. data/lib/gemba/recorder_decoder.rb +325 -0
  26. data/lib/gemba/rom_info_window.rb +346 -0
  27. data/lib/gemba/rom_loader.rb +100 -0
  28. data/lib/gemba/runtime.rb +39 -0
  29. data/lib/gemba/save_state_manager.rb +155 -0
  30. data/lib/gemba/save_state_picker.rb +199 -0
  31. data/lib/gemba/settings_window.rb +1173 -0
  32. data/lib/gemba/tip_service.rb +133 -0
  33. data/lib/gemba/toast_overlay.rb +128 -0
  34. data/lib/gemba/version.rb +5 -0
  35. data/lib/gemba.rb +17 -0
  36. data/test/fixtures/test.gba +0 -0
  37. data/test/fixtures/test.sav +0 -0
  38. data/test/shared/screenshot_helper.rb +113 -0
  39. data/test/shared/simplecov_config.rb +59 -0
  40. data/test/shared/teek_test_worker.rb +388 -0
  41. data/test/shared/tk_test_helper.rb +354 -0
  42. data/test/support/input_mocks.rb +61 -0
  43. data/test/support/player_helpers.rb +77 -0
  44. data/test/test_cli.rb +281 -0
  45. data/test/test_config.rb +897 -0
  46. data/test/test_core.rb +401 -0
  47. data/test/test_gamepad_map.rb +116 -0
  48. data/test/test_headless_player.rb +205 -0
  49. data/test/test_helper.rb +19 -0
  50. data/test/test_hotkey_map.rb +396 -0
  51. data/test/test_keyboard_map.rb +108 -0
  52. data/test/test_locale.rb +159 -0
  53. data/test/test_mgba.rb +26 -0
  54. data/test/test_overlay_renderer.rb +199 -0
  55. data/test/test_player.rb +903 -0
  56. data/test/test_recorder.rb +180 -0
  57. data/test/test_rom_loader.rb +149 -0
  58. data/test/test_save_state_manager.rb +289 -0
  59. data/test/test_settings_hotkeys.rb +434 -0
  60. data/test/test_settings_window.rb +1039 -0
  61. data/test/test_tip_service.rb +138 -0
  62. data/test/test_toast_overlay.rb +216 -0
  63. data/test/test_virtual_keyboard.rb +39 -0
  64. data/test/test_xor_delta.rb +61 -0
  65. metadata +234 -0
@@ -0,0 +1,199 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "minitest/autorun"
4
+ require_relative "../lib/gemba/overlay_renderer"
5
+
6
+ class TestOverlayRenderer < Minitest::Test
7
+ class MockTexture
8
+ attr_reader :calls, :width, :height
9
+ attr_accessor :blend_mode
10
+
11
+ def initialize(w, h)
12
+ @width = w
13
+ @height = h
14
+ @blend_mode = nil
15
+ @calls = []
16
+ end
17
+
18
+ def destroy
19
+ @calls << [:destroy]
20
+ end
21
+ end
22
+
23
+ class MockFont
24
+ attr_reader :calls
25
+
26
+ def initialize
27
+ @calls = []
28
+ end
29
+
30
+ def ascent = 10
31
+ def measure(_text) = [100, 14]
32
+
33
+ def render_text(text, r, g, b)
34
+ @calls << [:render_text, text]
35
+ MockTexture.new(text.length * 7, 14)
36
+ end
37
+ end
38
+
39
+ class MockRenderer
40
+ attr_reader :calls
41
+
42
+ def initialize
43
+ @calls = []
44
+ end
45
+
46
+ def output_size = [720, 480]
47
+
48
+ def copy(tex, src, dst)
49
+ @calls << [:copy, src, dst]
50
+ end
51
+ end
52
+
53
+ BLEND_MODE = 42 # arbitrary integer standing in for the real blend mode
54
+
55
+ def setup
56
+ @font = MockFont.new
57
+ @hud = Gemba::OverlayRenderer.new(font: @font, blend_mode: BLEND_MODE)
58
+ end
59
+
60
+ # -- initial state ---------------------------------------------------------
61
+
62
+ def test_not_visible_initially
63
+ refute @hud.fps_visible?
64
+ refute @hud.ff_visible?
65
+ end
66
+
67
+ # -- set_fps ---------------------------------------------------------------
68
+
69
+ def test_set_fps_makes_visible
70
+ @hud.set_fps("60.0 FPS")
71
+ assert @hud.fps_visible?
72
+ end
73
+
74
+ def test_set_fps_nil_hides
75
+ @hud.set_fps("60.0 FPS")
76
+ @hud.set_fps(nil)
77
+ refute @hud.fps_visible?
78
+ end
79
+
80
+ def test_set_fps_renders_text
81
+ @hud.set_fps("59.7 FPS")
82
+ assert_equal 1, @font.calls.size
83
+ assert_equal "59.7 FPS", @font.calls[0][1]
84
+ end
85
+
86
+ def test_set_fps_applies_blend_mode
87
+ @hud.set_fps("60 FPS")
88
+ tex = @font.calls.size # just verify render was called
89
+ assert_equal 1, tex
90
+ end
91
+
92
+ def test_set_fps_destroys_previous
93
+ @hud.set_fps("60.0 FPS")
94
+ first_render = @font.calls.size
95
+ @hud.set_fps("30.0 FPS")
96
+ assert_equal 2, @font.calls.size
97
+ end
98
+
99
+ # -- set_ff_label ----------------------------------------------------------
100
+
101
+ def test_set_ff_label_makes_visible
102
+ @hud.set_ff_label(">> 2x")
103
+ assert @hud.ff_visible?
104
+ end
105
+
106
+ def test_set_ff_label_nil_hides
107
+ @hud.set_ff_label(">> 2x")
108
+ @hud.set_ff_label(nil)
109
+ refute @hud.ff_visible?
110
+ end
111
+
112
+ # -- draw ------------------------------------------------------------------
113
+
114
+ def test_draw_does_nothing_when_empty
115
+ r = MockRenderer.new
116
+ @hud.draw(r, nil)
117
+ assert_empty r.calls
118
+ end
119
+
120
+ def test_draw_fps_top_right
121
+ @hud.set_fps("60 FPS")
122
+ r = MockRenderer.new
123
+ @hud.draw(r, [0, 0, 720, 480], show_fps: true)
124
+ copy_calls = r.calls.select { |c| c[0] == :copy }
125
+ assert_equal 1, copy_calls.size
126
+ dst = copy_calls[0][2]
127
+ # Should be near the right edge
128
+ assert dst[0] > 600, "FPS should be positioned near right edge, got x=#{dst[0]}"
129
+ end
130
+
131
+ def test_draw_ff_top_left
132
+ @hud.set_ff_label(">> 2x")
133
+ r = MockRenderer.new
134
+ @hud.draw(r, [0, 0, 720, 480], show_ff: true)
135
+ copy_calls = r.calls.select { |c| c[0] == :copy }
136
+ assert_equal 1, copy_calls.size
137
+ dst = copy_calls[0][2]
138
+ # Should be near the left edge
139
+ assert_equal 4, dst[0]
140
+ assert_equal 4, dst[1]
141
+ end
142
+
143
+ def test_draw_both
144
+ @hud.set_fps("60 FPS")
145
+ @hud.set_ff_label(">> MAX")
146
+ r = MockRenderer.new
147
+ @hud.draw(r, [0, 0, 720, 480], show_fps: true, show_ff: true)
148
+ copy_calls = r.calls.select { |c| c[0] == :copy }
149
+ assert_equal 2, copy_calls.size
150
+ end
151
+
152
+ def test_draw_respects_show_fps_false
153
+ @hud.set_fps("60 FPS")
154
+ r = MockRenderer.new
155
+ @hud.draw(r, nil, show_fps: false)
156
+ assert_empty r.calls
157
+ end
158
+
159
+ def test_draw_respects_show_ff_false
160
+ @hud.set_ff_label(">> 2x")
161
+ r = MockRenderer.new
162
+ @hud.draw(r, nil, show_ff: false)
163
+ assert_empty r.calls
164
+ end
165
+
166
+ def test_draw_offsets_by_dest_rect
167
+ @hud.set_ff_label(">> 2x")
168
+ r = MockRenderer.new
169
+ @hud.draw(r, [100, 50, 500, 400], show_ff: true)
170
+ dst = r.calls[0][2]
171
+ assert_equal 104, dst[0] # 100 + 4
172
+ assert_equal 54, dst[1] # 50 + 4
173
+ end
174
+
175
+ def test_draw_uses_output_size_when_no_dest
176
+ @hud.set_fps("60 FPS")
177
+ r = MockRenderer.new
178
+ @hud.draw(r, nil, show_fps: true)
179
+ dst = r.calls[0][2]
180
+ # x should be relative to output_size width (720)
181
+ assert dst[0] < 720
182
+ assert dst[0] > 600
183
+ end
184
+
185
+ # -- destroy ---------------------------------------------------------------
186
+
187
+ def test_destroy_clears_all
188
+ @hud.set_fps("60 FPS")
189
+ @hud.set_ff_label(">> 2x")
190
+ @hud.destroy
191
+ refute @hud.fps_visible?
192
+ refute @hud.ff_visible?
193
+ end
194
+
195
+ def test_destroy_safe_when_empty
196
+ @hud.destroy # should not raise
197
+ refute @hud.fps_visible?
198
+ end
199
+ end