1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package gpu_tests
import platform "../platform"
import "core:testing"
import window "window:window"
@(test)
test_register_action :: proc(t: ^testing.T) {
state: platform.Action_State
id1 := platform.register_action(&state, "jump")
testing.expect(t, id1 == 1, "first action should be 1")
id2 := platform.register_action(&state, "shoot")
testing.expect(t, id2 == 2, "second action should be 2")
testing.expect(t, platform.get_action_name(&state, id1) == "jump")
testing.expect(t, platform.get_action_name(&state, id2) == "shoot")
}
@(test)
test_register_invalid :: proc(t: ^testing.T) {
state: platform.Action_State
testing.expect(t, platform.get_action_name(&state, 0) == "", "action 0 should be invalid")
testing.expect(t, platform.get_action_name(&state, 99) == "", "out of range should be empty")
}
@(test)
test_bind_and_query_bindings :: proc(t: ^testing.T) {
state: platform.Action_State
id := platform.register_action(&state, "move_left")
platform.bind_action_key(&state, id, .A)
platform.bind_action_key(&state, id, .Arrow_Left)
bindings := platform.get_action_bindings(&state, id)
testing.expect(t, len(bindings) == 2, "should have 2 bindings")
// First binding should be Key A
k1, k1_ok := bindings[0].(window.Key_Code)
testing.expect(t, k1_ok && k1 == .A, "first binding should be A")
// Second binding should be Arrow_Left
k2, k2_ok := bindings[1].(window.Key_Code)
testing.expect(t, k2_ok && k2 == .Arrow_Left, "second binding should be Arrow_Left")
}
@(test)
test_bind_mouse :: proc(t: ^testing.T) {
state: platform.Action_State
id := platform.register_action(&state, "shoot")
platform.bind_action_key(&state, id, .Z)
platform.bind_action_mouse(&state, id, .Left)
bindings := platform.get_action_bindings(&state, id)
testing.expect(t, len(bindings) == 2, "should have 2 bindings")
_, is_key := bindings[0].(window.Key_Code)
testing.expect(t, is_key, "first should be key")
_, is_mouse := bindings[1].(window.Mouse_Button)
testing.expect(t, is_mouse, "second should be mouse button")
}
@(test)
test_unbind :: proc(t: ^testing.T) {
state: platform.Action_State
id := platform.register_action(&state, "jump")
platform.bind_action_key(&state, id, .Space)
platform.bind_action_key(&state, id, .W)
testing.expect(t, len(platform.get_action_bindings(&state, id)) == 2)
platform.unbind_action(&state, id)
testing.expect(
t,
len(platform.get_action_bindings(&state, id)) == 0,
"should have no bindings after unbind",
)
// Rebind to a different key
platform.bind_action_key(&state, id, .Enter)
bindings := platform.get_action_bindings(&state, id)
testing.expect(t, len(bindings) == 1, "should have 1 binding after rebind")
k, ok := bindings[0].(window.Key_Code)
testing.expect(t, ok && k == .Enter, "rebind should be Enter")
}
@(test)
test_max_bindings :: proc(t: ^testing.T) {
state: platform.Action_State
id := platform.register_action(&state, "test")
platform.bind_action_key(&state, id, .A)
platform.bind_action_key(&state, id, .B)
platform.bind_action_key(&state, id, .C)
platform.bind_action_key(&state, id, .D)
// 5th should be silently ignored
platform.bind_action_key(&state, id, .E)
bindings := platform.get_action_bindings(&state, id)
testing.expect(t, len(bindings) == 4, "should cap at MAX_BINDINGS_PER_ACTION")
}
@(test)
test_action_pressed :: proc(t: ^testing.T) {
pstate: platform.Platform_State
id := platform.register_action(&pstate.actions, "jump")
platform.bind_action_key(&pstate.actions, id, .Space)
// Simulate: key not pressed
testing.expect(t, !platform.is_action_pressed(&pstate, id), "should not be pressed initially")
testing.expect(t, !platform.is_action_down(&pstate, id), "should not be down initially")
// Simulate: key pressed this frame (current=true, previous=false)
pstate.input.keys_current[int(window.Key_Code.Space)] = true
testing.expect(
t,
platform.is_action_pressed(&pstate, id),
"should be pressed when key just went down",
)
testing.expect(t, platform.is_action_down(&pstate, id), "should be down when key is held")
// Simulate: key held (current=true, previous=true)
pstate.input.keys_previous[int(window.Key_Code.Space)] = true
testing.expect(
t,
!platform.is_action_pressed(&pstate, id),
"should not be 'pressed' when held",
)
testing.expect(t, platform.is_action_down(&pstate, id), "should still be down")
// Simulate: key released (current=false, previous=true)
pstate.input.keys_current[int(window.Key_Code.Space)] = false
testing.expect(t, platform.is_action_released(&pstate, id), "should be released")
testing.expect(t, !platform.is_action_down(&pstate, id), "should not be down after release")
}
@(test)
test_action_multiple_bindings :: proc(t: ^testing.T) {
pstate: platform.Platform_State
id := platform.register_action(&pstate.actions, "move")
platform.bind_action_key(&pstate.actions, id, .A)
platform.bind_action_key(&pstate.actions, id, .Arrow_Left)
// Neither pressed
testing.expect(t, !platform.is_action_down(&pstate, id))
// Only second binding pressed
pstate.input.keys_current[int(window.Key_Code.Arrow_Left)] = true
testing.expect(t, platform.is_action_down(&pstate, id), "should be down from Arrow_Left")
testing.expect(t, platform.is_action_pressed(&pstate, id), "should be pressed from Arrow_Left")
}
@(test)
test_invalid_action_queries :: proc(t: ^testing.T) {
pstate: platform.Platform_State
// Querying invalid/unregistered actions should return false
testing.expect(t, !platform.is_action_pressed(&pstate, 0))
testing.expect(t, !platform.is_action_down(&pstate, 0))
testing.expect(t, !platform.is_action_released(&pstate, 0))
testing.expect(t, !platform.is_action_pressed(&pstate, 99))
}