@inglorious/utils 3.6.3 → 3.7.1
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.
- package/README.md +1 -1
- package/package.json +5 -4
- package/src/data-structures/object.js +96 -3
- package/src/algorithms/decision-tree.test.js +0 -154
- package/src/algorithms/path-finding.test.js +0 -151
- package/src/data-structures/array.test.js +0 -206
- package/src/data-structures/board.test.js +0 -242
- package/src/data-structures/heap.test.js +0 -103
- package/src/data-structures/object.test.js +0 -335
- package/src/data-structures/objects.test.js +0 -196
- package/src/data-structures/set.test.js +0 -15
- package/src/data-structures/tree.test.js +0 -33
- package/src/functions/function.test.js +0 -15
- package/src/functions/functions.test.js +0 -51
- package/src/math/circle.test.js +0 -98
- package/src/math/hitmask.test.js +0 -156
- package/src/math/line.test.js +0 -50
- package/src/math/numbers.test.js +0 -198
- package/src/math/point.test.js +0 -94
- package/src/math/quaternion.test.js +0 -25
- package/src/math/quaternions.test.js +0 -29
- package/src/math/rectangle.test.js +0 -43
- package/src/math/rng.test.js +0 -55
- package/src/math/segment.test.js +0 -184
- package/src/math/statistics.test.js +0 -47
- package/src/math/triangle.test.js +0 -11
- package/src/math/trigonometry.test.js +0 -52
- package/src/math/vector.test.js +0 -345
- package/src/math/vectors.test.js +0 -77
- package/src/physics/friction.test.js +0 -43
- package/src/physics/gravity.test.js +0 -78
- package/src/v.test.js +0 -48
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "vitest"
|
|
2
|
-
|
|
3
|
-
import { mod } from "../math/numbers.js"
|
|
4
|
-
import {
|
|
5
|
-
createBoard,
|
|
6
|
-
down,
|
|
7
|
-
downLeft,
|
|
8
|
-
downRight,
|
|
9
|
-
left,
|
|
10
|
-
right,
|
|
11
|
-
toString,
|
|
12
|
-
up,
|
|
13
|
-
upLeft,
|
|
14
|
-
upRight,
|
|
15
|
-
} from "./board.js"
|
|
16
|
-
|
|
17
|
-
test("it should create an empty board", () => {
|
|
18
|
-
const size = [4, 4]
|
|
19
|
-
const expectedResult = [
|
|
20
|
-
null,
|
|
21
|
-
null,
|
|
22
|
-
null,
|
|
23
|
-
null,
|
|
24
|
-
null,
|
|
25
|
-
null,
|
|
26
|
-
null,
|
|
27
|
-
null,
|
|
28
|
-
null,
|
|
29
|
-
null,
|
|
30
|
-
null,
|
|
31
|
-
null,
|
|
32
|
-
null,
|
|
33
|
-
null,
|
|
34
|
-
null,
|
|
35
|
-
null,
|
|
36
|
-
]
|
|
37
|
-
|
|
38
|
-
expect(createBoard(size)).toStrictEqual(expectedResult)
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
test("it should create a checkerboard", () => {
|
|
42
|
-
const size = [4, 4]
|
|
43
|
-
const filler = (i, j) => (!mod(i + j, 2) ? 1 : 0)
|
|
44
|
-
const expectedResult = [1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1]
|
|
45
|
-
|
|
46
|
-
expect(createBoard(size, filler)).toStrictEqual(expectedResult)
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
test("it should return the coordinates of the cell downward", () => {
|
|
50
|
-
const size = [8, 8]
|
|
51
|
-
const coordinates = [3, 4]
|
|
52
|
-
const expectedResult = [4, 4]
|
|
53
|
-
|
|
54
|
-
expect(down(coordinates, size)).toStrictEqual(expectedResult)
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
test("it should throw going down if cell is downmost", () => {
|
|
58
|
-
const size = [8, 8]
|
|
59
|
-
const coordinates = [7, 4]
|
|
60
|
-
|
|
61
|
-
expect(() => down(coordinates, size)).toThrow()
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
test("it should return the coordinates of the cell down left", () => {
|
|
65
|
-
const size = [8, 8]
|
|
66
|
-
const coordinates = [3, 4]
|
|
67
|
-
const expectedResult = [4, 3]
|
|
68
|
-
|
|
69
|
-
expect(downLeft(coordinates, size)).toStrictEqual(expectedResult)
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
test("it should throw going down left if cell is downmost", () => {
|
|
73
|
-
const size = [8, 8]
|
|
74
|
-
const coordinates = [7, 4]
|
|
75
|
-
|
|
76
|
-
expect(() => downLeft(coordinates, size)).toThrow()
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
test("it should throw going down left if cell is downmost", () => {
|
|
80
|
-
const size = [8, 8]
|
|
81
|
-
const coordinates = [3, 0]
|
|
82
|
-
|
|
83
|
-
expect(() => downLeft(coordinates, size)).toThrow()
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
test("it should throw going down left if cell is on the angle", () => {
|
|
87
|
-
const size = [8, 8]
|
|
88
|
-
const coordinates = [7, 0]
|
|
89
|
-
|
|
90
|
-
expect(() => downLeft(coordinates, size)).toThrow()
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
test("it should return the coordinates of the cell down right", () => {
|
|
94
|
-
const size = [8, 8]
|
|
95
|
-
const coordinates = [3, 4]
|
|
96
|
-
const expectedResult = [4, 5]
|
|
97
|
-
|
|
98
|
-
expect(downRight(coordinates, size)).toStrictEqual(expectedResult)
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
test("it should throw going down right if cell is downmost", () => {
|
|
102
|
-
const size = [8, 8]
|
|
103
|
-
const coordinates = [7, 4]
|
|
104
|
-
|
|
105
|
-
expect(() => downRight(coordinates, size)).toThrow()
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
test("it should throw going down right if cell is downmost", () => {
|
|
109
|
-
const size = [8, 8]
|
|
110
|
-
const coordinates = [3, 7]
|
|
111
|
-
|
|
112
|
-
expect(() => downRight(coordinates, size)).toThrow()
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
test("it should throw going down right if cell is on the angle", () => {
|
|
116
|
-
const size = [8, 8]
|
|
117
|
-
const coordinates = [7, 7]
|
|
118
|
-
|
|
119
|
-
expect(() => downRight(coordinates, size)).toThrow()
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
test("it should return the coordinates of the cell to the left", () => {
|
|
123
|
-
const size = [8, 8]
|
|
124
|
-
const coordinates = [3, 4]
|
|
125
|
-
const expectedResult = [3, 3]
|
|
126
|
-
|
|
127
|
-
expect(left(coordinates, size)).toStrictEqual(expectedResult)
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
test("it should not return coordinates to the left if cell is leftmost", () => {
|
|
131
|
-
const size = [8, 8]
|
|
132
|
-
const coordinates = [3, 0]
|
|
133
|
-
|
|
134
|
-
expect(() => left(coordinates, size)).toThrow()
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
test("it should return the coordinates of the cell to the right", () => {
|
|
138
|
-
const size = [8, 8]
|
|
139
|
-
const coordinates = [3, 4]
|
|
140
|
-
const expectedResult = [3, 5]
|
|
141
|
-
|
|
142
|
-
expect(right(coordinates, size)).toStrictEqual(expectedResult)
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
test("it should not return coordinates to the right if cell is rightmost", () => {
|
|
146
|
-
const size = [8, 8]
|
|
147
|
-
const coordinates = [3, 7]
|
|
148
|
-
|
|
149
|
-
expect(() => right(coordinates, size)).toThrow()
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
test("it should return a string representation of the given board", () => {
|
|
153
|
-
const board = [1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1]
|
|
154
|
-
|
|
155
|
-
expect(toString(board, [4, 4])).toBe(`1 0 1 0
|
|
156
|
-
0 1 0 1
|
|
157
|
-
1 0 1 0
|
|
158
|
-
0 1 0 1`)
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
test("it should return a custom string representation of the given board", () => {
|
|
162
|
-
const board = [1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1]
|
|
163
|
-
const cellToString = (cell) => cell.toFixed(1)
|
|
164
|
-
|
|
165
|
-
expect(toString(board, [4, 4], cellToString)).toBe(`1.0 0.0 1.0 0.0
|
|
166
|
-
0.0 1.0 0.0 1.0
|
|
167
|
-
1.0 0.0 1.0 0.0
|
|
168
|
-
0.0 1.0 0.0 1.0`)
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
test("it should return the coordinates of the cell upward", () => {
|
|
172
|
-
const size = [8, 8]
|
|
173
|
-
const coordinates = [3, 4]
|
|
174
|
-
const expectedResult = [2, 4]
|
|
175
|
-
|
|
176
|
-
expect(up(coordinates, size)).toStrictEqual(expectedResult)
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
test("it should throw going upward if cell is topmost", () => {
|
|
180
|
-
const size = [8, 8]
|
|
181
|
-
const coordinates = [0, 4]
|
|
182
|
-
|
|
183
|
-
expect(() => up(coordinates, size)).toThrow()
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
test("it should return the coordinates of the cell up left", () => {
|
|
187
|
-
const size = [8, 8]
|
|
188
|
-
const coordinates = [3, 4]
|
|
189
|
-
const expectedResult = [2, 3]
|
|
190
|
-
|
|
191
|
-
expect(upLeft(coordinates, size)).toStrictEqual(expectedResult)
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
test("it should throw going up left if cell is upmost", () => {
|
|
195
|
-
const size = [8, 8]
|
|
196
|
-
const coordinates = [0, 4]
|
|
197
|
-
|
|
198
|
-
expect(() => upLeft(coordinates, size)).toThrow()
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
test("it should throw going up left if cell is leftmost", () => {
|
|
202
|
-
const size = [8, 8]
|
|
203
|
-
const coordinates = [3, 0]
|
|
204
|
-
|
|
205
|
-
expect(() => upLeft(coordinates, size)).toThrow()
|
|
206
|
-
})
|
|
207
|
-
|
|
208
|
-
test("it should throw going up left if cell is on the angle", () => {
|
|
209
|
-
const size = [8, 8]
|
|
210
|
-
const coordinates = [0, 0]
|
|
211
|
-
|
|
212
|
-
expect(() => upLeft(coordinates, size)).toThrow()
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
test("it should return the coordinates of the cell up right", () => {
|
|
216
|
-
const size = [8, 8]
|
|
217
|
-
const coordinates = [3, 4]
|
|
218
|
-
const expectedResult = [2, 5]
|
|
219
|
-
|
|
220
|
-
expect(upRight(coordinates, size)).toStrictEqual(expectedResult)
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
test("it should throw going up right if cell is upmost", () => {
|
|
224
|
-
const size = [8, 8]
|
|
225
|
-
const coordinates = [0, 4]
|
|
226
|
-
|
|
227
|
-
expect(() => upRight(coordinates, size)).toThrow()
|
|
228
|
-
})
|
|
229
|
-
|
|
230
|
-
test("it should throw going down right if cell is rightmost", () => {
|
|
231
|
-
const size = [8, 8]
|
|
232
|
-
const coordinates = [3, 7]
|
|
233
|
-
|
|
234
|
-
expect(() => upRight(coordinates, size)).toThrow()
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
test("it should throw going down right if cell is on the angle", () => {
|
|
238
|
-
const size = [8, 8]
|
|
239
|
-
const coordinates = [0, 7]
|
|
240
|
-
|
|
241
|
-
expect(() => upRight(coordinates, size)).toThrow()
|
|
242
|
-
})
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "vitest"
|
|
2
|
-
|
|
3
|
-
import { contains, heapify, pop, push, remove, root } from "./heap.js"
|
|
4
|
-
|
|
5
|
-
test("it should check if a heap contains a value", () => {
|
|
6
|
-
const heap = [3, 2, 6, 1, 7, 4, 5]
|
|
7
|
-
const item = 1
|
|
8
|
-
const expectedResult = true
|
|
9
|
-
|
|
10
|
-
expect(contains(heap, item)).toBe(expectedResult)
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
test("it should check if a heap contains an object", () => {
|
|
14
|
-
const heap = [
|
|
15
|
-
{ value: 3 },
|
|
16
|
-
{ value: 2 },
|
|
17
|
-
{ value: 6 },
|
|
18
|
-
{ value: 1 },
|
|
19
|
-
{ value: 7 },
|
|
20
|
-
{ value: 4 },
|
|
21
|
-
{ value: 5 },
|
|
22
|
-
]
|
|
23
|
-
const item = heap[3]
|
|
24
|
-
const expectedResult = true
|
|
25
|
-
|
|
26
|
-
expect(contains(heap, item)).toBe(expectedResult)
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
test("it should not convert an array in existing heap form into a heap", () => {
|
|
30
|
-
const arr = [1, 2, 3, 4, 5, 6, 7]
|
|
31
|
-
const expectedResult = [1, 2, 3, 4, 5, 6, 7]
|
|
32
|
-
|
|
33
|
-
expect(heapify(arr)).toStrictEqual(expectedResult)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
test("it should convert an array into a heap", () => {
|
|
37
|
-
const arr = [7, 6, 5, 4, 3, 2, 1]
|
|
38
|
-
const expectedResult = [1, 4, 2, 7, 5, 6, 3]
|
|
39
|
-
|
|
40
|
-
expect(heapify(arr)).toStrictEqual(expectedResult)
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
test("it should convert an array into a maxheap", () => {
|
|
44
|
-
const arr = [1, 2, 3, 4, 5, 6, 7]
|
|
45
|
-
const comparator = (a, b) => a - b
|
|
46
|
-
const expectedResult = [7, 4, 6, 1, 3, 2, 5]
|
|
47
|
-
|
|
48
|
-
expect(heapify(arr, comparator)).toStrictEqual(expectedResult)
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
test("it should find the minimum value in a min heap", () => {
|
|
52
|
-
const heap = [1, 4, 2, 7, 5, 6, 3]
|
|
53
|
-
const expectedResult = 1
|
|
54
|
-
|
|
55
|
-
expect(root(heap)).toBe(expectedResult)
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test("it should push the first element of the heap", () => {
|
|
59
|
-
const heap = []
|
|
60
|
-
const value = 7
|
|
61
|
-
const expectedResult = [7]
|
|
62
|
-
|
|
63
|
-
expect(push(heap, value)).toStrictEqual(expectedResult)
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
test("it should push the biggest value at the end of the heap", () => {
|
|
67
|
-
const heap = [3, 13, 19, 33, 42, 23, 21]
|
|
68
|
-
const value = 50
|
|
69
|
-
const expectedResult = [3, 13, 19, 33, 42, 23, 21, 50]
|
|
70
|
-
|
|
71
|
-
expect(push(heap, value)).toStrictEqual(expectedResult)
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
test("it should push a value in the right spot of a heap", () => {
|
|
75
|
-
const heap = [3, 13, 19, 33, 42, 23, 21]
|
|
76
|
-
const value = 7
|
|
77
|
-
const expectedResult = [3, 7, 19, 13, 42, 23, 21, 33]
|
|
78
|
-
|
|
79
|
-
expect(push(heap, value)).toStrictEqual(expectedResult)
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
test("it should pop the lowest value from the end of the heap", () => {
|
|
83
|
-
const heap = [3, 13, 19, 33, 42, 23, 21]
|
|
84
|
-
const expectedResult = [13, 21, 19, 33, 42, 23]
|
|
85
|
-
|
|
86
|
-
expect(pop(heap)).toStrictEqual(expectedResult)
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
test("it should push the biggest value at the beginning of a maxheap", () => {
|
|
90
|
-
const heap = [3, 13, 19, 33, 42, 23, 21]
|
|
91
|
-
const comparator = (a, b) => a - b
|
|
92
|
-
const value = 50
|
|
93
|
-
const expectedResult = [50, 3, 19, 13, 42, 23, 21, 33]
|
|
94
|
-
|
|
95
|
-
expect(push(heap, value, comparator)).toStrictEqual(expectedResult)
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
test("it should remove the heap's root element", () => {
|
|
99
|
-
const heap = [3, 13, 19, 33, 42, 23, 21]
|
|
100
|
-
const expectedResult = [13, 21, 19, 33, 42, 23]
|
|
101
|
-
|
|
102
|
-
expect(remove(heap)).toStrictEqual(expectedResult)
|
|
103
|
-
})
|
|
@@ -1,335 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "vitest"
|
|
2
|
-
|
|
3
|
-
import { v } from "../v.js"
|
|
4
|
-
import {
|
|
5
|
-
clone,
|
|
6
|
-
deserialize,
|
|
7
|
-
filter,
|
|
8
|
-
find,
|
|
9
|
-
isObject,
|
|
10
|
-
map,
|
|
11
|
-
produce,
|
|
12
|
-
serialize,
|
|
13
|
-
toString,
|
|
14
|
-
} from "./object.js"
|
|
15
|
-
|
|
16
|
-
test("it should deep clone an object", () => {
|
|
17
|
-
const obj = {
|
|
18
|
-
primitive: 1,
|
|
19
|
-
array: [2, 3],
|
|
20
|
-
object: { a: 1, b: 2 },
|
|
21
|
-
}
|
|
22
|
-
const expectedResult = {
|
|
23
|
-
primitive: 1,
|
|
24
|
-
array: [2, 3],
|
|
25
|
-
object: { a: 1, b: 2 },
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const result = clone(obj)
|
|
29
|
-
|
|
30
|
-
expect(result).toStrictEqual(expectedResult)
|
|
31
|
-
expect(result).not.toBe(expectedResult)
|
|
32
|
-
expect(result.primitive).toBe(expectedResult.primitive)
|
|
33
|
-
expect(result.array).not.toBe(expectedResult.array)
|
|
34
|
-
expect(result.object).not.toBe(expectedResult.object)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test("it should behave like Array.prototype.filter, but on an object", () => {
|
|
38
|
-
const obj = {
|
|
39
|
-
key1: "value1",
|
|
40
|
-
key2: "value2",
|
|
41
|
-
key3: "value3",
|
|
42
|
-
}
|
|
43
|
-
const callback = (key) => ["key2", "key3"].includes(key)
|
|
44
|
-
const expectedResult = {
|
|
45
|
-
key2: "value2",
|
|
46
|
-
key3: "value3",
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
expect(filter(obj, callback)).toStrictEqual(expectedResult)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
test("it should behave like Array.prototype.find, but on an object", () => {
|
|
53
|
-
const obj = {
|
|
54
|
-
key1: "value1",
|
|
55
|
-
key2: "value2",
|
|
56
|
-
key3: "value3",
|
|
57
|
-
}
|
|
58
|
-
const callback = (key) => ["key2", "key3"].includes(key)
|
|
59
|
-
const expectedResult = {
|
|
60
|
-
key2: "value2",
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
expect(find(obj, callback)).toStrictEqual(expectedResult)
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
test("it correctly should check if a value is an object", () => {
|
|
67
|
-
expect(isObject(1)).toBe(false)
|
|
68
|
-
expect(isObject("a")).toBe(false)
|
|
69
|
-
expect(isObject([])).toBe(false)
|
|
70
|
-
expect(isObject(null)).toBe(false)
|
|
71
|
-
expect(isObject(new Date())).toBe(false)
|
|
72
|
-
expect(isObject({})).toBe(true)
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
test("it should behave like Array.prototype.map, but on an object", () => {
|
|
76
|
-
const obj = {
|
|
77
|
-
key1: "value1",
|
|
78
|
-
key2: "value2",
|
|
79
|
-
key3: "value3",
|
|
80
|
-
}
|
|
81
|
-
const callback = (key, value) => value.toUpperCase()
|
|
82
|
-
const expectedResult = {
|
|
83
|
-
key1: "VALUE1",
|
|
84
|
-
key2: "VALUE2",
|
|
85
|
-
key3: "VALUE3",
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
expect(map(obj, callback)).toStrictEqual(expectedResult)
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
test("it should produce a new state without mutating the original", () => {
|
|
92
|
-
const baseState = {
|
|
93
|
-
a: 1,
|
|
94
|
-
b: {
|
|
95
|
-
c: [2, 3],
|
|
96
|
-
d: { e: 4 },
|
|
97
|
-
},
|
|
98
|
-
f: 5,
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const recipe = (draft) => {
|
|
102
|
-
draft.a = 10
|
|
103
|
-
draft.b.c.push(4)
|
|
104
|
-
draft.b.d.e = 40
|
|
105
|
-
draft.g = 6
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const expectedState = {
|
|
109
|
-
a: 10,
|
|
110
|
-
b: {
|
|
111
|
-
c: [2, 3, 4],
|
|
112
|
-
d: { e: 40 },
|
|
113
|
-
},
|
|
114
|
-
f: 5,
|
|
115
|
-
g: 6,
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const originalBaseState = deserialize(serialize(baseState))
|
|
119
|
-
|
|
120
|
-
const nextState = produce(baseState, recipe)
|
|
121
|
-
|
|
122
|
-
expect(nextState).toStrictEqual(expectedState)
|
|
123
|
-
expect(nextState).not.toBe(baseState)
|
|
124
|
-
expect(baseState).toStrictEqual(originalBaseState)
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
test("it should support currying to produce a new state", () => {
|
|
128
|
-
const baseState = {
|
|
129
|
-
a: 1,
|
|
130
|
-
b: {
|
|
131
|
-
c: [2, 3],
|
|
132
|
-
d: { e: 4 },
|
|
133
|
-
},
|
|
134
|
-
f: 5,
|
|
135
|
-
}
|
|
136
|
-
const originalStateCopy = clone(baseState)
|
|
137
|
-
|
|
138
|
-
const recipe = (draft) => {
|
|
139
|
-
draft.a = 10
|
|
140
|
-
draft.b.c.push(4)
|
|
141
|
-
draft.g = 6
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const expectedState = {
|
|
145
|
-
a: 10,
|
|
146
|
-
b: {
|
|
147
|
-
c: [2, 3, 4],
|
|
148
|
-
d: { e: 4 },
|
|
149
|
-
},
|
|
150
|
-
f: 5,
|
|
151
|
-
g: 6,
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const producer = produce(recipe)
|
|
155
|
-
const nextState = producer(baseState)
|
|
156
|
-
|
|
157
|
-
expect(nextState).toStrictEqual(expectedState)
|
|
158
|
-
expect(nextState).not.toBe(baseState)
|
|
159
|
-
expect(baseState).toStrictEqual(originalStateCopy)
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
test("it should pass extra arguments to the recipe", () => {
|
|
163
|
-
const baseState = { value: 1 }
|
|
164
|
-
const recipe = (draft, increment, multiplier) => {
|
|
165
|
-
draft.value = (draft.value + increment) * multiplier
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Test non-curried version
|
|
169
|
-
const nextStateUncurried = produce(baseState, recipe, 2, 3) // (1 + 2) * 3 = 9
|
|
170
|
-
expect(nextStateUncurried.value).toBe(9)
|
|
171
|
-
|
|
172
|
-
// Test curried version
|
|
173
|
-
const producer = produce(recipe)
|
|
174
|
-
const nextStateCurried = producer(baseState, 4, 5) // (1 + 4) * 5 = 25
|
|
175
|
-
expect(nextStateCurried.value).toBe(25)
|
|
176
|
-
|
|
177
|
-
expect(baseState.value).toBe(1)
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
test("it should return a string representation of a shallow object", () => {
|
|
181
|
-
const obj = {
|
|
182
|
-
key1: "value1",
|
|
183
|
-
key2: "value2",
|
|
184
|
-
key3: "value3",
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
expect(toString(obj)).toBe(`{
|
|
188
|
-
key1: "value1",
|
|
189
|
-
key2: "value2",
|
|
190
|
-
key3: "value3"
|
|
191
|
-
}`)
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
test("it should return a string representation of a nested object", () => {
|
|
195
|
-
const obj = {
|
|
196
|
-
a: 1,
|
|
197
|
-
b: [7, 3],
|
|
198
|
-
c: { d: 4, h: 8 },
|
|
199
|
-
e: [{ f: 5, i: 9 }],
|
|
200
|
-
g: 6,
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
expect(toString(obj)).toBe(`{
|
|
204
|
-
a: 1,
|
|
205
|
-
b: [
|
|
206
|
-
7,
|
|
207
|
-
3
|
|
208
|
-
],
|
|
209
|
-
c: {
|
|
210
|
-
d: 4,
|
|
211
|
-
h: 8
|
|
212
|
-
},
|
|
213
|
-
e: [
|
|
214
|
-
{
|
|
215
|
-
f: 5,
|
|
216
|
-
i: 9
|
|
217
|
-
}
|
|
218
|
-
],
|
|
219
|
-
g: 6
|
|
220
|
-
}`)
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
test("it should serialize a basic object with primitive values", () => {
|
|
224
|
-
const obj = { a: 1, b: "hello", c: true }
|
|
225
|
-
const expected = `{"a":1,"b":"hello","c":true}`
|
|
226
|
-
|
|
227
|
-
expect(serialize(obj)).toBe(expected)
|
|
228
|
-
})
|
|
229
|
-
|
|
230
|
-
test("it should serialize an object with nested objects", () => {
|
|
231
|
-
const obj = { a: 1, b: { c: "nested", d: { e: false } } }
|
|
232
|
-
const expected = `{"a":1,"b":{"c":"nested","d":{"e":false}}}`
|
|
233
|
-
|
|
234
|
-
expect(serialize(obj)).toBe(expected)
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
test("it should serialize an object containing a vector-like object", () => {
|
|
238
|
-
const obj = { position: v(1, 2, 3) }
|
|
239
|
-
const expected = `{"position":{"_type":"vector","coords":[1,2,3]}}`
|
|
240
|
-
|
|
241
|
-
expect(serialize(obj)).toBe(expected)
|
|
242
|
-
})
|
|
243
|
-
|
|
244
|
-
test("it should serialize an object with nested vector-like objects", () => {
|
|
245
|
-
const obj = {
|
|
246
|
-
entity: {
|
|
247
|
-
id: "player",
|
|
248
|
-
pos: v(10, 20),
|
|
249
|
-
vel: v(1, 0),
|
|
250
|
-
stats: { health: 100 },
|
|
251
|
-
},
|
|
252
|
-
}
|
|
253
|
-
const expected = `{"entity":{"id":"player","pos":{"_type":"vector","coords":[10,20]},"vel":{"_type":"vector","coords":[1,0]},"stats":{"health":100}}}`
|
|
254
|
-
|
|
255
|
-
expect(serialize(obj)).toBe(expected)
|
|
256
|
-
})
|
|
257
|
-
|
|
258
|
-
test("it should serialize an empty object", () => {
|
|
259
|
-
const obj = {}
|
|
260
|
-
const expected = `{}`
|
|
261
|
-
|
|
262
|
-
expect(serialize(obj)).toBe(expected)
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
test("it should serialize an object with null and undefined values (undefined should be omitted)", () => {
|
|
266
|
-
const obj = { a: null, b: undefined, c: 1 }
|
|
267
|
-
const expected = `{"a":null,"c":1}` // JSON.stringify omits undefined properties
|
|
268
|
-
|
|
269
|
-
expect(serialize(obj)).toBe(expected)
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
test("it should deserialize a basic object with primitive values", () => {
|
|
273
|
-
const serialized = `{"a":1,"b":"hello","c":true}`
|
|
274
|
-
const expected = { a: 1, b: "hello", c: true }
|
|
275
|
-
|
|
276
|
-
expect(deserialize(serialized)).toStrictEqual(expected)
|
|
277
|
-
})
|
|
278
|
-
|
|
279
|
-
test("it should deserialize an object with nested objects", () => {
|
|
280
|
-
const serialized = `{"a":1,"b":{"c":"nested","d":{"e":false}}}`
|
|
281
|
-
const expected = { a: 1, b: { c: "nested", d: { e: false } } }
|
|
282
|
-
|
|
283
|
-
expect(deserialize(serialized)).toStrictEqual(expected)
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
test("it should deserialize an object containing a vector representation", () => {
|
|
287
|
-
const serialized = `{"position":{"_type":"vector","coords":[1,2,3]}}`
|
|
288
|
-
const expected = { position: v(1, 2, 3) }
|
|
289
|
-
|
|
290
|
-
const result = deserialize(serialized)
|
|
291
|
-
|
|
292
|
-
expect(result).toStrictEqual(expected)
|
|
293
|
-
expect(result.position.__isVector__).toBe(true)
|
|
294
|
-
})
|
|
295
|
-
|
|
296
|
-
test("it should deserialize an object with nested vector representations", () => {
|
|
297
|
-
const serialized = `{"entity":{"id":"player","pos":{"_type":"vector","coords":[10,20]},"vel":{"_type":"vector","coords":[1,0]},"stats":{"health":100}}}`
|
|
298
|
-
const expected = {
|
|
299
|
-
entity: {
|
|
300
|
-
id: "player",
|
|
301
|
-
pos: v(10, 20),
|
|
302
|
-
vel: v(1, 0),
|
|
303
|
-
stats: { health: 100 },
|
|
304
|
-
},
|
|
305
|
-
}
|
|
306
|
-
const result = deserialize(serialized)
|
|
307
|
-
|
|
308
|
-
expect(result).toStrictEqual(expected)
|
|
309
|
-
expect(result.entity.pos.__isVector__).toBe(true)
|
|
310
|
-
expect(result.entity.vel.__isVector__).toBe(true)
|
|
311
|
-
})
|
|
312
|
-
|
|
313
|
-
test("it should deserialize an empty object", () => {
|
|
314
|
-
const serialized = `{}`
|
|
315
|
-
const expected = {}
|
|
316
|
-
|
|
317
|
-
expect(deserialize(serialized)).toStrictEqual(expected)
|
|
318
|
-
})
|
|
319
|
-
|
|
320
|
-
test("it should correctly round-trip a complex object through serialize and deserialize", () => {
|
|
321
|
-
const original = {
|
|
322
|
-
id: "game1",
|
|
323
|
-
player: { name: "Alice", score: 100, position: v(10, 20) },
|
|
324
|
-
enemies: [{ type: "goblin", pos: v(5, 5) }],
|
|
325
|
-
settings: { volume: 0.8, mute: false },
|
|
326
|
-
}
|
|
327
|
-
const jsonString = serialize(original)
|
|
328
|
-
const deserialized = deserialize(jsonString)
|
|
329
|
-
|
|
330
|
-
expect(deserialized).toStrictEqual(original)
|
|
331
|
-
expect(deserialized.player.position.__isVector__).toBe(true)
|
|
332
|
-
expect(deserialized.enemies[0].pos.__isVector__).toBe(true)
|
|
333
|
-
// Ensure that non-vector objects are still distinct references if they were originally
|
|
334
|
-
expect(deserialized.player).not.toBe(original.player)
|
|
335
|
-
})
|