Skip to content

Commit ecff6e4

Browse files
committed
add unit tests
1 parent 7fb9d2a commit ecff6e4

File tree

3 files changed

+229
-9
lines changed

3 files changed

+229
-9
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/**
2+
* @fileoverview Tests for blankControls utility
3+
*/
4+
5+
import { describe, it, expect } from 'vitest'
6+
import { blankControls } from './blankControls'
7+
8+
describe('blankControls', () => {
9+
it('creates blank controls with all values false', () => {
10+
const source = {
11+
a: true,
12+
b: true,
13+
c: true
14+
}
15+
16+
const result = blankControls(source)
17+
18+
expect(result).toEqual({
19+
a: false,
20+
b: false,
21+
c: false
22+
})
23+
})
24+
25+
it('preserves keys from source regardless of their values', () => {
26+
const source = {
27+
foo: false,
28+
bar: false,
29+
baz: false
30+
}
31+
32+
const result = blankControls(source)
33+
34+
expect(result).toEqual({
35+
foo: false,
36+
bar: false,
37+
baz: false
38+
})
39+
})
40+
41+
it('applies overrides to specific controls', () => {
42+
const source = {
43+
a: true,
44+
b: true,
45+
c: true
46+
}
47+
48+
const result = blankControls(source, { b: true })
49+
50+
expect(result).toEqual({
51+
a: false,
52+
b: true,
53+
c: false
54+
})
55+
})
56+
57+
it('applies multiple overrides', () => {
58+
const source = {
59+
x: true,
60+
y: true,
61+
z: true
62+
}
63+
64+
const result = blankControls(source, { x: true, z: true })
65+
66+
expect(result).toEqual({
67+
x: true,
68+
y: false,
69+
z: true
70+
})
71+
})
72+
73+
it('works with no overrides', () => {
74+
const source = {
75+
thrust: true,
76+
fire: true,
77+
shield: true
78+
}
79+
80+
const result = blankControls(source, {})
81+
82+
expect(result).toEqual({
83+
thrust: false,
84+
fire: false,
85+
shield: false
86+
})
87+
})
88+
89+
it('handles source with different property names', () => {
90+
const source = {
91+
propA: true,
92+
propB: false,
93+
propC: true
94+
}
95+
96+
const result = blankControls(source, { propC: true })
97+
98+
expect(result.propA).toBe(false)
99+
expect(result.propB).toBe(false)
100+
expect(result.propC).toBe(true)
101+
})
102+
})

src/core/controls/blankControls.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
* @fileoverview Utility for creating blank control matrices
33
*/
44

5-
import type { ControlMatrix } from './types'
6-
75
/**
86
* Creates a blank control matrix with all controls set to false.
97
* Optionally allows specific controls to be overridden.
@@ -12,16 +10,16 @@ import type { ControlMatrix } from './types'
1210
* @param overrides - Optional partial control matrix to override specific controls
1311
* @returns A complete control matrix with all controls false except overrides
1412
*/
15-
export function blankControls(
16-
source: ControlMatrix,
17-
overrides?: Partial<ControlMatrix>
18-
): ControlMatrix {
19-
const blank = {} as ControlMatrix
20-
const keys = Object.keys(source) as (keyof ControlMatrix)[]
13+
export function blankControls<T extends Record<string, boolean>>(
14+
source: T,
15+
overrides?: Partial<T>
16+
): T {
17+
const blank = {} as T
18+
const keys = Object.keys(source) as (keyof T)[]
2119

2220
// Set all controls to false
2321
for (const key of keys) {
24-
blank[key] = overrides?.[key] ?? false
22+
blank[key] = (overrides?.[key] ?? false) as T[keyof T]
2523
}
2624

2725
return blank
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/**
2+
* @fileoverview Tests for mergeControls utility
3+
*/
4+
5+
import { describe, it, expect } from 'vitest'
6+
import { mergeControls } from './mergeControls'
7+
8+
describe('mergeControls', () => {
9+
it('merges two control sets with OR logic', () => {
10+
const controls1 = {
11+
a: true,
12+
b: false,
13+
c: true
14+
}
15+
16+
const controls2 = {
17+
a: false,
18+
b: true,
19+
c: true
20+
}
21+
22+
const result = mergeControls(controls1, controls2)
23+
24+
expect(result).toEqual({
25+
a: true, // true OR false = true
26+
b: true, // false OR true = true
27+
c: true // true OR true = true
28+
})
29+
})
30+
31+
it('handles all false controls', () => {
32+
const controls1 = {
33+
x: false,
34+
y: false,
35+
z: false
36+
}
37+
38+
const controls2 = {
39+
x: false,
40+
y: false,
41+
z: false
42+
}
43+
44+
const result = mergeControls(controls1, controls2)
45+
46+
expect(result).toEqual({
47+
x: false,
48+
y: false,
49+
z: false
50+
})
51+
})
52+
53+
it('handles all true in first set', () => {
54+
const controls1 = {
55+
foo: true,
56+
bar: true
57+
}
58+
59+
const controls2 = {
60+
foo: false,
61+
bar: false
62+
}
63+
64+
const result = mergeControls(controls1, controls2)
65+
66+
expect(result).toEqual({
67+
foo: true,
68+
bar: true
69+
})
70+
})
71+
72+
it('merges more than two control sets', () => {
73+
const controls1 = {
74+
a: true,
75+
b: false,
76+
c: false
77+
}
78+
79+
const controls2 = {
80+
a: false,
81+
b: true,
82+
c: false
83+
}
84+
85+
const controls3 = {
86+
a: false,
87+
b: false,
88+
c: true
89+
}
90+
91+
const result = mergeControls(controls1, controls2, controls3)
92+
93+
expect(result.a).toBe(true)
94+
expect(result.b).toBe(true)
95+
expect(result.c).toBe(true)
96+
})
97+
98+
it('works with different property names', () => {
99+
const controls1 = {
100+
thrust: true,
101+
shield: false
102+
}
103+
104+
const controls2 = {
105+
thrust: false,
106+
shield: true
107+
}
108+
109+
const result = mergeControls(controls1, controls2)
110+
111+
expect(result.thrust).toBe(true)
112+
expect(result.shield).toBe(true)
113+
})
114+
115+
it('throws error when called with no arguments', () => {
116+
expect(() => mergeControls()).toThrow(
117+
'mergeControls requires at least one control set'
118+
)
119+
})
120+
})

0 commit comments

Comments
 (0)