Files
2026-10-18 16:32:07 -05:00

119 lines
4.5 KiB
JavaScript

const {test} = require('node:test');
const fs = require('node:fs');
const path = require('node:path');
const assert = require('node:assert');
const VirtualMachine = require('../../src/virtual-machine');
const Sampler = require('../../src/engine/tw-sampler');
const FakeRenderer = require('../fixtures/fake-renderer');
const fixture = fs.readFileSync(path.join(__dirname, '../fixtures/tw-sampler.sb3'));
// The runtime skips drawing when the document is hidden
global.document = {
hidden: false
};
const setup = async () => {
const vm = new VirtualMachine();
const renderer = new FakeRenderer();
vm.attachRenderer(renderer);
await vm.loadProject(fixture);
// Value of pc each time a block moved the sprite and each time the renderer drew.
// Bounded so that a broken test can't eat all memory.
const moves = [];
const draws = [];
const getPC = () => (vm.runtime.sampler.pc ? vm.runtime.sampler.pc[0] : null);
const originalUpdateDrawablePosition = renderer.updateDrawablePosition;
renderer.updateDrawablePosition = function (...args) {
if (moves.length < 100) moves.push(getPC());
return originalUpdateDrawablePosition.apply(this, args);
};
renderer.draw = () => {
if (draws.length < 100) draws.push(getPC());
};
return {vm, moves, draws};
};
test('blockToLocation is stable and per-sprite', () => {
const sampler = new Sampler(null);
const a = sampler.blockToLocation('sprite1', 'block1');
const b = sampler.blockToLocation('sprite1', 'block2');
const c = sampler.blockToLocation('sprite2', 'block1');
assert.notStrictEqual(a, b);
assert.notStrictEqual(a, c);
assert.ok(a >= 0 && b >= 0 && c >= 0);
assert.strictEqual(sampler.blockToLocation('sprite1', 'block1'), a);
assert.deepStrictEqual(sampler.locationToBlock(c), {
spriteId: 'sprite2',
blockId: 'block1'
});
assert.throws(() => sampler.locationToBlock(Sampler.IDLE));
});
test('disabled by default', async () => {
const {vm, moves, draws} = await setup();
vm.greenFlag();
vm.runtime._step();
assert.strictEqual(vm.runtime.sampler.pc, null);
assert.deepStrictEqual(moves, [null, null]);
assert.deepStrictEqual(draws, [null]);
assert.strictEqual(vm.runtime.sampler.locations.length, 0);
});
test('basic level attributes compiled scripts to RUNTIME', async () => {
const {vm, moves, draws} = await setup();
vm.runtime.sampler.setEnabled(Sampler.LEVEL_BASIC);
vm.greenFlag();
vm.runtime._step();
assert.ok(vm.runtime.threads[0].isCompiled);
assert.deepStrictEqual(moves, [Sampler.RUNTIME, Sampler.RUNTIME]);
assert.deepStrictEqual(draws, [Sampler.RENDERER]);
assert.strictEqual(vm.runtime.sampler.pc[0], Sampler.IDLE);
assert.strictEqual(vm.runtime.sampler.locations.length, 0);
});
test('commands level attributes compiled scripts to blocks', async () => {
const {vm, moves, draws} = await setup();
const sampler = vm.runtime.sampler;
sampler.setEnabled(Sampler.LEVEL_COMMANDS);
vm.greenFlag();
vm.runtime._step();
assert.ok(vm.runtime.threads[0].isCompiled);
const spriteId = vm.runtime.getSpriteTargetByName('Sprite1').id;
const changeOnce = sampler.blockToLocation(spriteId, 'b');
const changeInLoop = sampler.blockToLocation(spriteId, 'f');
assert.deepStrictEqual(moves, [changeOnce, changeInLoop]);
assert.deepStrictEqual(draws, [Sampler.RENDERER]);
assert.strictEqual(sampler.pc[0], Sampler.IDLE);
// After resuming from the loop's yield
vm.runtime._step();
assert.deepStrictEqual(moves, [changeOnce, changeInLoop, changeInLoop]);
assert.deepStrictEqual(draws, [Sampler.RENDERER, Sampler.RENDERER]);
assert.strictEqual(sampler.pc[0], Sampler.IDLE);
});
test('setEnabled(0) turns sampling back off', async () => {
const {vm, moves, draws} = await setup();
vm.runtime.sampler.setEnabled(Sampler.LEVEL_COMMANDS);
vm.runtime.sampler.setEnabled(0);
assert.strictEqual(vm.runtime.sampler.enableBasic, false);
assert.strictEqual(vm.runtime.sampler.enableCommands, false);
// pc is kept around but no longer written to
vm.runtime.sampler.pc[0] = 1234;
vm.greenFlag();
vm.runtime._step();
assert.deepStrictEqual(moves, [1234, 1234]);
assert.deepStrictEqual(draws, [1234]);
assert.strictEqual(vm.runtime.sampler.locations.length, 0);
});
test('Sampler is exported', () => {
const vm = new VirtualMachine();
assert.strictEqual(vm.exports.Sampler, Sampler);
});