From 5ef246a2b0b7587d8c133a175c7c320503415f0d Mon Sep 17 00:00:00 2001 From: Karishma Chadha <kchadha@scratch.mit.edu> Date: Wed, 8 Aug 2018 18:29:54 -0400 Subject: [PATCH 1/2] Export the sprite and return an add function when deleting the sprite. --- src/virtual-machine.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/virtual-machine.js b/src/virtual-machine.js index b1b186972..9dff04722 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -836,6 +836,7 @@ class VirtualMachine extends EventEmitter { /** * Delete a sprite and all its clones. * @param {string} targetId ID of a target whose sprite to delete. + * @return {Function} Returns a function to restore the sprite that was deleted */ deleteSprite (targetId) { const target = this.runtime.getTargetById(targetId); @@ -849,6 +850,10 @@ class VirtualMachine extends EventEmitter { if (!sprite) { throw new Error('No sprite associated with this target.'); } + const spritePromise = this.exportSprite(targetId, 'uint8array'); + const restoreSprite = () => { + spritePromise.then(spriteBuffer => this.addSprite(spriteBuffer)); + }; this.runtime.requestRemoveMonitorByTargetId(targetId); const currentEditingTarget = this.editingTarget; for (let i = 0; i < sprite.clones.length; i++) { @@ -867,9 +872,10 @@ class VirtualMachine extends EventEmitter { } // Sprite object should be deleted by GC. this.emitTargetsUpdate(); - } else { - throw new Error('No target with the provided id.'); + return restoreSprite; } + + throw new Error('No target with the provided id.'); } /** From a1f03f58e1843e237b317f8a394123fe6ec6c1a6 Mon Sep 17 00:00:00 2001 From: Karishma Chadha <kchadha@scratch.mit.edu> Date: Thu, 9 Aug 2018 11:53:37 -0400 Subject: [PATCH 2/2] Add integration test for deleting and restoring a sprite, and restoreFunciton should return a promise. --- src/virtual-machine.js | 4 +- test/integration/delete-and-restore-sprite.js | 65 +++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 test/integration/delete-and-restore-sprite.js diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 9dff04722..1828db5fd 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -851,9 +851,7 @@ class VirtualMachine extends EventEmitter { throw new Error('No sprite associated with this target.'); } const spritePromise = this.exportSprite(targetId, 'uint8array'); - const restoreSprite = () => { - spritePromise.then(spriteBuffer => this.addSprite(spriteBuffer)); - }; + const restoreSprite = () => spritePromise.then(spriteBuffer => this.addSprite(spriteBuffer)); this.runtime.requestRemoveMonitorByTargetId(targetId); const currentEditingTarget = this.editingTarget; for (let i = 0; i < sprite.clones.length; i++) { diff --git a/test/integration/delete-and-restore-sprite.js b/test/integration/delete-and-restore-sprite.js new file mode 100644 index 000000000..9ed1c781c --- /dev/null +++ b/test/integration/delete-and-restore-sprite.js @@ -0,0 +1,65 @@ +const path = require('path'); +const test = require('tap').test; +const makeTestStorage = require('../fixtures/make-test-storage'); +const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; + +const VirtualMachine = require('../../src/virtual-machine'); +// const RenderedTarget = require('../../src/sprites/rendered-target'); + +const projectUri = path.resolve(__dirname, '../fixtures/default.sb2'); +const project = readFileToBuffer(projectUri); + +const vm = new VirtualMachine(); + +test('spec', t => { + t.type(vm.deleteSprite, 'function'); + t.end(); +}); + +test('default cat', t => { + // Get default cat from .sprite2 + // const uri = path.resolve(__dirname, '../fixtures/example_sprite.sprite2'); + // const sprite = readFileToBuffer(uri); + + vm.attachStorage(makeTestStorage()); + + // Evaluate playground data and exit + vm.on('playgroundData', e => { + const threads = JSON.parse(e.threads); + t.ok(threads.length === 0); + t.end(); + process.nextTick(process.exit); + }); + + vm.start(); + vm.clear(); + vm.setCompatibilityMode(false); + vm.setTurboMode(false); + t.doesNotThrow(() => { + vm.loadProject(project).then(() => { + + t.equal(vm.runtime.targets.length, 2); // stage and default sprite + + const defaultSprite = vm.runtime.targets[1]; + + // Delete the sprite + const addSpriteBack = vm.deleteSprite(vm.runtime.targets[1].id); + + t.equal(vm.runtime.targets.length, 1); + + t.type(addSpriteBack, 'function'); + + addSpriteBack().then(() => { + t.equal(vm.runtime.targets.length, 2); + t.equal(vm.runtime.targets[1].getName(), defaultSprite.getName()); + + vm.greenFlag(); + + setTimeout(() => { + vm.getPlaygroundData(); + vm.stopAll(); + }, 1000); + }); + }); + }); +});