Spaces:
Running
Running
const test = require('tap').test; | |
const Blocks = require('../../src/engine/blocks'); | |
const Clone = require('../../src/util/clone'); | |
const {loadCostume} = require('../../src/import/load-costume'); | |
const {loadSound} = require('../../src/import/load-sound'); | |
const makeTestStorage = require('../fixtures/make-test-storage'); | |
const Runtime = require('../../src/engine/runtime'); | |
const sb3 = require('../../src/serialization/sb3'); | |
const Sprite = require('../../src/sprites/sprite'); | |
const defaultCostumeInfo = { | |
bitmapResolution: 1, | |
rotationCenterX: 0, | |
rotationCenterY: 0 | |
}; | |
const defaultSoundInfo = { | |
}; | |
test('sb3-roundtrip', t => { | |
const runtime1 = new Runtime(); | |
runtime1.attachStorage(makeTestStorage()); | |
const runtime2 = new Runtime(); | |
runtime2.attachStorage(makeTestStorage()); | |
const testRuntimeState = (label, runtime) => { | |
t.strictEqual(runtime.targets.length, 2, `${label}: target count`); | |
const [stageClone, spriteClone] = runtime.targets; | |
t.strictEqual(stageClone.isOriginal, true); | |
t.strictEqual(stageClone.isStage, true); | |
const stage = stageClone.sprite; | |
t.strictEqual(stage.name, 'Stage'); | |
t.strictEqual(stage.clones.length, 1); | |
t.strictEqual(stage.clones[0], stageClone); | |
t.strictEqual(stage.costumes.length, 1); | |
const [building] = stage.costumes; | |
t.strictEqual(building.assetId, 'fe5e3566965f9de793beeffce377d054'); | |
t.strictEqual(building.dataFormat, 'jpg'); | |
t.strictEqual(stage.sounds.length, 0); | |
t.strictEqual(spriteClone.isOriginal, true); | |
t.strictEqual(spriteClone.isStage, false); | |
const sprite = spriteClone.sprite; | |
t.strictEqual(sprite.name, 'Sprite'); | |
t.strictEqual(sprite.clones.length, 1); | |
t.strictEqual(sprite.clones[0], spriteClone); | |
t.strictEqual(sprite.costumes.length, 2); | |
const [cat, squirrel] = sprite.costumes; | |
t.strictEqual(cat.assetId, 'f88bf1935daea28f8ca098462a31dbb0'); | |
t.strictEqual(cat.dataFormat, 'svg'); | |
t.strictEqual(squirrel.assetId, '7e24c99c1b853e52f8e7f9004416fa34'); | |
t.strictEqual(squirrel.dataFormat, 'png'); | |
t.strictEqual(sprite.sounds.length, 1); | |
const [meow] = sprite.sounds; | |
t.strictEqual(meow.md5, '83c36d806dc92327b9e7049a565c6bff.wav'); | |
}; | |
const loadThings = Promise.all([ | |
loadCostume('fe5e3566965f9de793beeffce377d054.jpg', Clone.simple(defaultCostumeInfo), runtime1), | |
loadCostume('f88bf1935daea28f8ca098462a31dbb0.svg', Clone.simple(defaultCostumeInfo), runtime1), | |
loadCostume('7e24c99c1b853e52f8e7f9004416fa34.png', Clone.simple(defaultCostumeInfo), runtime1), | |
loadSound(Object.assign({md5: '83c36d806dc92327b9e7049a565c6bff.wav'}, defaultSoundInfo), runtime1) | |
]); | |
const installThings = loadThings.then(results => { | |
const [building, cat, squirrel, meow] = results; | |
const stageBlocks = new Blocks(runtime1); | |
const stage = new Sprite(stageBlocks, runtime1); | |
stage.name = 'Stage'; | |
stage.costumes = [building]; | |
stage.sounds = []; | |
const stageClone = stage.createClone(); | |
stageClone.isStage = true; | |
const spriteBlocks = new Blocks(runtime1); | |
const sprite = new Sprite(spriteBlocks, runtime1); | |
sprite.name = 'Sprite'; | |
sprite.costumes = [cat, squirrel]; | |
sprite.sounds = [meow]; | |
const spriteClone = sprite.createClone(); | |
runtime1.targets = [stageClone, spriteClone]; | |
testRuntimeState('original', runtime1); | |
}); | |
const serializeAndDeserialize = installThings.then(() => { | |
// Doing a JSON `stringify` and `parse` here more accurately simulate a save/load cycle. In particular: | |
// 1. it ensures that any non-serializable data is thrown away, and | |
// 2. `sb3.deserialize` and its helpers do some `hasOwnProperty` checks which fail on the object returned by | |
// `sb3.serialize` but succeed if that object is "flattened" in this way. | |
const serializedState = JSON.parse(JSON.stringify(sb3.serialize(runtime1))); | |
return sb3.deserialize(serializedState, runtime2); | |
}); | |
return serializeAndDeserialize.then(({targets}) => { | |
runtime2.targets = targets; | |
testRuntimeState('copy', runtime2); | |
}); | |
}); | |