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);
+            });
+        });
+    });
+});