From 8bbb395b35d2532b0b20e40d94fa4798f5b10fba Mon Sep 17 00:00:00 2001
From: Paul Kaplan <pkaplan@media.mit.edu>
Date: Mon, 20 Mar 2017 12:52:57 -0400
Subject: [PATCH] Add sprite name incrementing and reserved naming

---
 src/virtual-machine.js       | 13 +++++++++++--
 test/integration/complex.js  |  2 +-
 test/unit/virtual-machine.js | 35 ++++++++++++++++++++++++++++++++++-
 3 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/src/virtual-machine.js b/src/virtual-machine.js
index aae77937d..576e3a78a 100644
--- a/src/virtual-machine.js
+++ b/src/virtual-machine.js
@@ -3,6 +3,9 @@ var util = require('util');
 
 var Runtime = require('./engine/runtime');
 var sb2import = require('./import/sb2import');
+var StringUtil = require('./util/string-util');
+
+var RESERVED_NAMES = ['_mouse_', '_stage_', '_edge_', '_myself_', '_random_'];
 
 /**
  * Handles connections between blocks, stage, and extensions.
@@ -204,8 +207,14 @@ VirtualMachine.prototype.renameSprite = function (targetId, newName) {
         if (!sprite) {
             throw new Error('No sprite associated with this target.');
         }
-        if (newName) {
-            sprite.name = newName;
+        if (newName && RESERVED_NAMES.indexOf(newName) === -1) {
+            var names = this.runtime.targets.filter(function (runtimeTarget) {
+                return runtimeTarget.isSprite();
+            }).map(function (runtimeTarget) {
+                return runtimeTarget.sprite.name;
+            });
+
+            sprite.name = StringUtil.unusedName(newName, names);
         }
         this.emitTargetsUpdate();
     } else {
diff --git a/test/integration/complex.js b/test/integration/complex.js
index dea8d40bc..f8dbd2cc2 100644
--- a/test/integration/complex.js
+++ b/test/integration/complex.js
@@ -26,7 +26,7 @@ test('complex', function (t) {
         var targets = data.targetList;
         for (var i in targets) {
             if (targets[i].isStage === true) continue;
-            if (targets[i].name === 'test') continue;
+            if (targets[i].name.match(/test/)) continue;
 
             vm.setEditingTarget(targets[i].id);
             vm.renameSprite(targets[i].id, 'test');
diff --git a/test/unit/virtual-machine.js b/test/unit/virtual-machine.js
index 28bcdd764..eed537dd3 100644
--- a/test/unit/virtual-machine.js
+++ b/test/unit/virtual-machine.js
@@ -50,7 +50,7 @@ test('renameSprite sets the sprite name', function (t) {
     t.end();
 });
 
-test('renameSprite does not set sprite names to an empty string ', function (t) {
+test('renameSprite does not set sprite names to an empty string', function (t) {
     var vm = new VirtualMachine();
     var fakeTarget = {
         sprite: {name: 'original'},
@@ -61,3 +61,36 @@ test('renameSprite does not set sprite names to an empty string ', function (t)
     t.equal(fakeTarget.sprite.name, 'original');
     t.end();
 });
+
+test('renameSprite does not set sprite names to reserved names', function (t) {
+    var vm = new VirtualMachine();
+    var fakeTarget = {
+        sprite: {name: 'original'},
+        isSprite: () => true
+    };
+    vm.runtime.getTargetById = () => (fakeTarget);
+    vm.renameSprite('id', '_mouse_');
+    t.equal(fakeTarget.sprite.name, 'original');
+    t.end();
+});
+
+test('renameSprite increments from existing sprite names', function (t) {
+    var vm = new VirtualMachine();
+    vm.emitTargetsUpdate = () => {};
+    vm.runtime.targets = [{
+        id: 'id1',
+        isSprite: () => true,
+        sprite: {
+            name: 'this name'
+        }
+    }, {
+        id: 'id2',
+        isSprite: () => true,
+        sprite: {
+            name: 'that name'
+        }
+    }];
+    vm.renameSprite('id1', 'that name');
+    t.equal(vm.runtime.targets[0].sprite.name, 'that name2');
+    t.end();
+});