Skip to content

Commit 662cbee

Browse files
committed
fix bad test and restore the GC heavy hack
1 parent d9c2d7b commit 662cbee

2 files changed

Lines changed: 129 additions & 21 deletions

File tree

packages/typegpu/tests/buffer.test.ts

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -469,28 +469,23 @@ describe('TgpuBuffer', () => {
469469

470470
it('should allow for partial writes', ({ root, device }) => {
471471
const buffer = root.createBuffer(d.struct({ a: d.u32, b: d.u32 }));
472-
473-
buffer.writePartial({ a: 3 });
474-
475472
const rawBuffer = root.unwrap(buffer);
476473
expect(rawBuffer).toBeDefined();
477474

475+
buffer.writePartial({ a: 3 });
478476
expect(device.mock.queue.writeBuffer.mock.calls).toStrictEqual([
479477
[rawBuffer, 0, toUint8Array(new Uint32Array([3]))],
480478
]);
479+
device.mock.queue.writeBuffer.mockClear();
481480

482481
buffer.writePartial({ b: 4 });
483-
484482
expect(device.mock.queue.writeBuffer.mock.calls).toStrictEqual([
485-
[rawBuffer, 0, toUint8Array(new Uint32Array([3]))],
486483
[rawBuffer, 4, toUint8Array(new Uint32Array([4]))],
487484
]);
485+
device.mock.queue.writeBuffer.mockClear();
488486

489487
buffer.writePartial({ a: 5, b: 6 }); // should merge the writes
490-
491488
expect(device.mock.queue.writeBuffer.mock.calls).toStrictEqual([
492-
[rawBuffer, 0, toUint8Array(new Uint32Array([3]))],
493-
[rawBuffer, 4, toUint8Array(new Uint32Array([4]))],
494489
[rawBuffer, 0, toUint8Array(new Uint32Array([5, 6]))],
495490
]);
496491
});
@@ -503,36 +498,32 @@ describe('TgpuBuffer', () => {
503498
d: d.arrayOf(d.u32, 3),
504499
}),
505500
);
506-
507-
buffer.writePartial({ a: 3 });
508-
509501
const rawBuffer = root.unwrap(buffer);
510502
expect(rawBuffer).toBeDefined();
511503

504+
buffer.writePartial({ a: 3 });
512505
expect(device.mock.queue.writeBuffer.mock.calls).toStrictEqual([
513506
[rawBuffer, 0, toUint8Array(new Uint32Array([3]))],
514507
]);
508+
device.mock.queue.writeBuffer.mockClear();
515509

516510
buffer.writePartial({ b: { c: d.vec2f(1, 2) } });
517-
518511
expect(device.mock.queue.writeBuffer.mock.calls).toStrictEqual([
519-
[rawBuffer, 0, toUint8Array(new Uint32Array([3]))],
520512
[rawBuffer, 8, toUint8Array(new Float32Array([1, 2]))],
521513
]);
514+
device.mock.queue.writeBuffer.mockClear();
522515

523516
buffer.writePartial({
524517
d: [
525518
{ idx: 0, value: 1 },
526519
{ idx: 2, value: 3 },
527520
],
528521
});
529-
530522
expect(device.mock.queue.writeBuffer.mock.calls).toStrictEqual([
531-
[rawBuffer, 0, toUint8Array(new Uint32Array([3]))],
532-
[rawBuffer, 8, toUint8Array(new Float32Array([1, 2]))],
533523
[rawBuffer, 16, toUint8Array(new Uint32Array([1]))],
534524
[rawBuffer, 24, toUint8Array(new Uint32Array([3]))],
535525
]);
526+
device.mock.queue.writeBuffer.mockClear();
536527

537528
buffer.writePartial({
538529
b: { c: d.vec2f(3, 4) },
@@ -541,12 +532,7 @@ describe('TgpuBuffer', () => {
541532
{ idx: 1, value: 3 },
542533
],
543534
}); // should merge the writes
544-
545535
expect(device.mock.queue.writeBuffer.mock.calls).toStrictEqual([
546-
[rawBuffer, 0, toUint8Array(new Uint32Array([3]))],
547-
[rawBuffer, 8, toUint8Array(new Float32Array([1, 2]))],
548-
[rawBuffer, 16, toUint8Array(new Uint32Array([1]))],
549-
[rawBuffer, 24, toUint8Array(new Uint32Array([3]))],
550536
[rawBuffer, 8, toUint8Array(new Float32Array([3, 4]), new Uint32Array([2, 3]))],
551537
]);
552538
});
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/**
2+
* Tests for getPatchInstructions when the compiled writer is unavailable
3+
* (CSP/eval-restricted environments). vi.mock is hoisted by vitest so this
4+
* file's entire module graph sees getCompiledWriter returning undefined,
5+
* forcing the typed-binary fallback path in partialIO.ts.
6+
*/
7+
import { describe, expect, vi } from 'vitest';
8+
import { it } from 'typegpu-testing-utility';
9+
import type { TypedArray } from '../src/shared/utilityTypes.ts';
10+
import type { WriteInstruction } from '../src/data/partialIO.ts';
11+
12+
vi.mock('../src/data/compiledIO.ts', () => ({
13+
EVAL_ALLOWED_IN_ENV: false,
14+
getCompiledWriter: () => undefined,
15+
buildWriter: () => '',
16+
}));
17+
18+
// Dynamic imports are required AFTER vi.mock to get the mocked versions.
19+
const { getPatchInstructions } = await import('../src/data/partialIO.ts');
20+
const d = await import('../src/data/index.ts');
21+
22+
function expectInstruction(
23+
instruction: WriteInstruction,
24+
{
25+
start,
26+
length,
27+
expectedData,
28+
}: {
29+
start: number;
30+
length: number;
31+
expectedData: TypedArray | TypedArray[];
32+
},
33+
): void {
34+
expect(instruction.gpuOffset).toBe(start);
35+
expect(instruction.data.byteLength).toBe(length);
36+
37+
const dataArrays = Array.isArray(expectedData) ? expectedData : [expectedData];
38+
const totalByteLength = dataArrays.reduce((acc, arr) => acc + arr.byteLength, 0);
39+
const mergedExpected = new Uint8Array(totalByteLength);
40+
let offset = 0;
41+
for (const arr of dataArrays) {
42+
mergedExpected.set(new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength), offset);
43+
offset += arr.byteLength;
44+
}
45+
46+
expect(instruction.data).toHaveLength(totalByteLength);
47+
expect(new Uint8Array(instruction.data)).toStrictEqual(mergedExpected);
48+
}
49+
50+
describe('getPatchInstructions (no-eval / typed-binary fallback)', () => {
51+
it('should produce correct instructions for a scalar', () => {
52+
const instructions = getPatchInstructions(d.u32, 3) as [WriteInstruction];
53+
expect(instructions).toHaveLength(1);
54+
expectInstruction(instructions[0], {
55+
start: 0,
56+
length: 4,
57+
expectedData: new Uint32Array([3]),
58+
});
59+
});
60+
61+
it('should produce correct instructions for a struct', () => {
62+
const struct = d.struct({
63+
a: d.u32,
64+
b: d.vec3f,
65+
c: d.struct({ d: d.u32 }),
66+
});
67+
68+
const instructions = getPatchInstructions(struct, {
69+
a: 3,
70+
b: d.vec3f(1, 2, 3),
71+
c: { d: 4 },
72+
}) as [WriteInstruction];
73+
74+
expect(instructions).toHaveLength(1);
75+
expectInstruction(instructions[0], {
76+
start: 0,
77+
length: 32,
78+
expectedData: [
79+
new Uint32Array([3, 0, 0, 0]),
80+
new Float32Array([1, 2, 3]),
81+
new Uint32Array([4]),
82+
],
83+
});
84+
});
85+
86+
it('should handle sparse array updates', () => {
87+
const struct = d.struct({
88+
a: d.u32,
89+
b: d.arrayOf(d.vec3f, 4),
90+
});
91+
92+
const instructions = getPatchInstructions(struct, {
93+
b: { 1: d.vec3f(4, 5, 6) },
94+
}) as [WriteInstruction];
95+
96+
expect(instructions).toHaveLength(1);
97+
expectInstruction(instructions[0], {
98+
start: 32, // offset of b[1]: 16 (b start) + 1 * 16 (element stride)
99+
length: 12,
100+
expectedData: new Float32Array([4, 5, 6]),
101+
});
102+
});
103+
104+
it('should split instructions at non-contiguous gaps', () => {
105+
const struct = d.struct({
106+
a: d.u32,
107+
b: d.vec3f,
108+
});
109+
110+
// Only patch b, leaving a out — creates a gap after start
111+
const instructions = getPatchInstructions(struct, { b: d.vec3f(1, 2, 3) }) as [
112+
WriteInstruction,
113+
];
114+
115+
expect(instructions).toHaveLength(1);
116+
expectInstruction(instructions[0], {
117+
start: 16,
118+
length: 12,
119+
expectedData: new Float32Array([1, 2, 3]),
120+
});
121+
});
122+
});

0 commit comments

Comments
 (0)