diff --git a/index.html b/index.html
index 9bb30b26ba..80c56a96bb 100644
--- a/index.html
+++ b/index.html
@@ -151,7 +151,7 @@
-
+
diff --git a/js/id/actions/copy_entities.js b/js/id/actions/copy_entities.js
new file mode 100644
index 0000000000..5c6a02850b
--- /dev/null
+++ b/js/id/actions/copy_entities.js
@@ -0,0 +1,21 @@
+iD.actions.CopyEntities = function(ids, fromGraph) {
+ var copies = {};
+
+ var action = function(graph) {
+ ids.forEach(function(id) {
+ fromGraph.entity(id).copy(fromGraph, copies);
+ });
+
+ for (var id in copies) {
+ graph = graph.replace(copies[id]);
+ }
+
+ return graph;
+ };
+
+ action.copies = function() {
+ return copies;
+ };
+
+ return action;
+};
diff --git a/js/id/actions/copy_entity.js b/js/id/actions/copy_entity.js
deleted file mode 100644
index 33a1cd0002..0000000000
--- a/js/id/actions/copy_entity.js
+++ /dev/null
@@ -1,21 +0,0 @@
-iD.actions.CopyEntity = function(id, fromGraph, deep) {
- var newEntities = [];
-
- var action = function(graph) {
- var entity = fromGraph.entity(id);
-
- newEntities = entity.copy(deep, fromGraph);
-
- for (var i = 0; i < newEntities.length; i++) {
- graph = graph.replace(newEntities[i]);
- }
-
- return graph;
- };
-
- action.newEntities = function() {
- return newEntities;
- };
-
- return action;
-};
diff --git a/js/id/behavior/paste.js b/js/id/behavior/paste.js
index ada7c1d901..82dd028daa 100644
--- a/js/id/behavior/paste.js
+++ b/js/id/behavior/paste.js
@@ -31,30 +31,21 @@ iD.behavior.Paste = function(context) {
var extent = iD.geo.Extent(),
oldIDs = context.copyIDs(),
oldGraph = context.copyGraph(),
- newIDs = [],
- i, j;
+ newIDs = [];
if (!oldIDs.length) return;
- for (i = 0; i < oldIDs.length; i++) {
- var oldEntity = oldGraph.entity(oldIDs[i]),
- action = iD.actions.CopyEntity(oldEntity.id, oldGraph, true),
- newEntities;
+ var action = iD.actions.CopyEntities(oldIDs, oldGraph);
+ context.perform(action);
- extent._extend(oldEntity.extent(oldGraph));
- context.perform(action);
-
- // First element in `newEntities` contains the copied Entity,
- // Subsequent array elements contain any descendants..
- newEntities = action.newEntities();
- newIDs.push(newEntities[0].id);
+ var copies = action.copies();
+ for (var id in copies) {
+ var oldEntity = oldGraph.entity(id),
+ newEntity = copies[id];
- for (j = 0; j < newEntities.length; j++) {
- var newEntity = newEntities[j],
- tags = _.omit(newEntity.tags, omitTag);
-
- context.perform(iD.actions.ChangeTags(newEntity.id, tags));
- }
+ extent._extend(oldEntity.extent(oldGraph));
+ newIDs.push(newEntity.id);
+ context.perform(iD.actions.ChangeTags(newEntity.id, _.omit(newEntity.tags, omitTag)));
}
// Put pasted objects where mouse pointer is..
diff --git a/js/id/core/entity.js b/js/id/core/entity.js
index b2bb88a7b7..2905a391e8 100644
--- a/js/id/core/entity.js
+++ b/js/id/core/entity.js
@@ -72,10 +72,14 @@ iD.Entity.prototype = {
return this;
},
- copy: function() {
- // Returns an array so that we can support deep copying ways and relations.
- // The first array element will contain this.copy, followed by any descendants.
- return [iD.Entity(this, {id: undefined, user: undefined, version: undefined})];
+ copy: function(resolver, copies) {
+ if (copies[this.id])
+ return copies[this.id];
+
+ var copy = iD.Entity(this, {id: undefined, user: undefined, version: undefined});
+ copies[this.id] = copy;
+
+ return copy;
},
osmId: function() {
diff --git a/js/id/core/relation.js b/js/id/core/relation.js
index 761db2a655..e318e8112e 100644
--- a/js/id/core/relation.js
+++ b/js/id/core/relation.js
@@ -20,31 +20,19 @@ _.extend(iD.Relation.prototype, {
type: 'relation',
members: [],
- copy: function(deep, resolver, replacements) {
- var copy = iD.Entity.prototype.copy.call(this);
- if (!deep || !resolver || !this.isComplete(resolver)) {
- return copy;
- }
+ copy: function(resolver, copies) {
+ if (copies[this.id])
+ return copies[this.id];
- var members = [],
- i, oldmember, oldid, newid, children;
+ var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
- replacements = replacements || {};
- replacements[this.id] = copy[0].id;
+ var members = this.members.map(function(member) {
+ return _.extend({}, member, {id: resolver.entity(member.id).copy(resolver, copies).id});
+ });
- for (i = 0; i < this.members.length; i++) {
- oldmember = this.members[i];
- oldid = oldmember.id;
- newid = replacements[oldid];
- if (!newid) {
- children = resolver.entity(oldid).copy(true, resolver, replacements);
- newid = replacements[oldid] = children[0].id;
- copy = copy.concat(children);
- }
- members.push({id: newid, type: oldmember.type, role: oldmember.role});
- }
+ copy = copy.update({members: members});
+ copies[this.id] = copy;
- copy[0] = copy[0].update({members: members});
return copy;
},
diff --git a/js/id/core/way.js b/js/id/core/way.js
index 7fad36eba3..ea56ba14de 100644
--- a/js/id/core/way.js
+++ b/js/id/core/way.js
@@ -12,29 +12,19 @@ _.extend(iD.Way.prototype, {
type: 'way',
nodes: [],
- copy: function(deep, resolver) {
- var copy = iD.Entity.prototype.copy.call(this);
+ copy: function(resolver, copies) {
+ if (copies[this.id])
+ return copies[this.id];
- if (!deep || !resolver) {
- return copy;
- }
+ var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
- var nodes = [],
- replacements = {},
- i, oldid, newid, child;
-
- for (i = 0; i < this.nodes.length; i++) {
- oldid = this.nodes[i];
- newid = replacements[oldid];
- if (!newid) {
- child = resolver.entity(oldid).copy();
- newid = replacements[oldid] = child[0].id;
- copy = copy.concat(child);
- }
- nodes.push(newid);
- }
+ var nodes = this.nodes.map(function(id) {
+ return resolver.entity(id).copy(resolver, copies).id;
+ });
+
+ copy = copy.update({nodes: nodes});
+ copies[this.id] = copy;
- copy[0] = copy[0].update({nodes: nodes});
return copy;
},
diff --git a/test/index.html b/test/index.html
index 890fbef0ec..9349a34a74 100644
--- a/test/index.html
+++ b/test/index.html
@@ -136,7 +136,7 @@
-
+
@@ -246,7 +246,7 @@
-
+
diff --git a/test/index_packaged.html b/test/index_packaged.html
index 4be2d344b7..96ff26064a 100644
--- a/test/index_packaged.html
+++ b/test/index_packaged.html
@@ -42,7 +42,7 @@
-
+
diff --git a/test/spec/actions/copy_entities.js b/test/spec/actions/copy_entities.js
new file mode 100644
index 0000000000..7e9728e276
--- /dev/null
+++ b/test/spec/actions/copy_entities.js
@@ -0,0 +1,71 @@
+describe("iD.actions.CopyEntities", function () {
+ it("copies a node", function () {
+ var a = iD.Node({id: 'a'}),
+ base = iD.Graph([a]),
+ head = iD.actions.CopyEntities(['a'], base)(base),
+ diff = iD.Difference(base, head),
+ created = diff.created();
+
+ expect(head.hasEntity('a')).to.be.ok;
+ expect(created).to.have.length(1);
+ });
+
+ it("copies a way", function () {
+ var a = iD.Node({id: 'a'}),
+ b = iD.Node({id: 'b'}),
+ w = iD.Way({id: 'w', nodes: ['a', 'b']}),
+ base = iD.Graph([a, b, w]),
+ action = iD.actions.CopyEntities(['w'], base),
+ head = action(base),
+ diff = iD.Difference(base, head),
+ created = diff.created();
+
+ expect(head.hasEntity('w')).to.be.ok;
+ expect(created).to.have.length(3);
+ });
+
+ it("copies multiple nodes", function () {
+ var base = iD.Graph([
+ iD.Node({id: 'a'}),
+ iD.Node({id: 'b'})
+ ]),
+ action = iD.actions.CopyEntities(['a', 'b'], base),
+ head = action(base),
+ diff = iD.Difference(base, head),
+ created = diff.created();
+
+ expect(head.hasEntity('a')).to.be.ok;
+ expect(head.hasEntity('b')).to.be.ok;
+ expect(created).to.have.length(2);
+ });
+
+ it("copies multiple ways, keeping the same connections", function () {
+ var base = iD.Graph([
+ iD.Node({id: 'a'}),
+ iD.Node({id: 'b'}),
+ iD.Node({id: 'c'}),
+ iD.Way({id: 'w1', nodes: ['a', 'b']}),
+ iD.Way({id: 'w2', nodes: ['b', 'c']})
+ ]),
+ action = iD.actions.CopyEntities(['w1', 'w2'], base),
+ head = action(base),
+ diff = iD.Difference(base, head),
+ created = diff.created();
+
+ expect(created).to.have.length(5);
+ expect(action.copies().w1.nodes[1]).to.eql(action.copies().w2.nodes[0]);
+ });
+
+ it("obtains source entities from an alternate graph", function () {
+ var a = iD.Node({id: 'a'}),
+ old = iD.Graph([a]),
+ base = iD.Graph(),
+ action = iD.actions.CopyEntities(['a'], old),
+ head = action(base),
+ diff = iD.Difference(base, head),
+ created = diff.created();
+
+ expect(head.hasEntity('a')).not.to.be.ok;
+ expect(Object.keys(action.copies())).to.have.length(1);
+ });
+});
diff --git a/test/spec/actions/copy_entity.js b/test/spec/actions/copy_entity.js
deleted file mode 100644
index 3b85f3ba97..0000000000
--- a/test/spec/actions/copy_entity.js
+++ /dev/null
@@ -1,106 +0,0 @@
-describe("iD.actions.CopyEntity", function () {
- it("copies a Node and adds it to the graph", function () {
- var a = iD.Node({id: 'a'}),
- base = iD.Graph([a]),
- head = iD.actions.CopyEntity('a', base, false)(base),
- diff = iD.Difference(base, head),
- created = diff.created();
-
- expect(head.hasEntity('a')).to.be.ok;
- expect(created).to.have.length(1);
- expect(created[0]).to.be.an.instanceof(iD.Node);
- });
-
- it("shallow copies a Way and adds it to the graph", function () {
- var a = iD.Node({id: 'a'}),
- b = iD.Node({id: 'b'}),
- w = iD.Way({id: 'w', nodes: ['a', 'b']}),
- base = iD.Graph([a, b, w]),
- head = iD.actions.CopyEntity('w', base, false)(base),
- diff = iD.Difference(base, head),
- created = diff.created();
-
- expect(head.hasEntity('w')).to.be.ok;
- expect(created).to.have.length(1);
- expect(created[0]).to.be.an.instanceof(iD.Way);
- });
-
- it("deep copies a Way and child Nodes and adds them to the graph", function () {
- var a = iD.Node({id: 'a'}),
- b = iD.Node({id: 'b'}),
- w = iD.Way({id: 'w', nodes: ['a', 'b']}),
- base = iD.Graph([a, b, w]),
- head = iD.actions.CopyEntity('w', base, true)(base),
- diff = iD.Difference(base, head),
- created = diff.created();
-
- expect(head.hasEntity('w')).to.be.ok;
- expect(created).to.have.length(3);
- expect(created[0]).to.be.an.instanceof(iD.Way);
- expect(created[1]).to.be.an.instanceof(iD.Node);
- expect(created[2]).to.be.an.instanceof(iD.Node);
- });
-
- it("shallow copies a Relation and adds it to the graph", function () {
- var a = iD.Node({id: 'a'}),
- b = iD.Node({id: 'b'}),
- w = iD.Way({id: 'w', nodes: ['a', 'b']}),
- r = iD.Relation({id: 'r', members: [{id: 'w'}]}),
- base = iD.Graph([a, b, w, r]),
- head = iD.actions.CopyEntity('r', base, false)(base),
- diff = iD.Difference(base, head),
- created = diff.created();
-
- expect(head.hasEntity('r')).to.be.ok;
- expect(created).to.have.length(1);
- expect(created[0]).to.be.an.instanceof(iD.Relation);
- });
-
- it("deep copies a Relation, member Ways, and child Nodes and adds them to the graph");//, function () {
- // var a = iD.Node({id: 'a'}),
- // b = iD.Node({id: 'b'}),
- // w = iD.Way({id: 'w', nodes: ['a', 'b']}),
- // r = iD.Relation({id: 'r', members: [{id: 'w'}]}),
- // base = iD.Graph([a, b, w, r]),
- // head = iD.actions.CopyEntity('r', base, true)(base),
- // diff = iD.Difference(base, head),
- // created = diff.created();
-
- // expect(head.hasEntity('r')).to.be.ok;
- // expect(created).to.have.length(4);
- // expect(created[0]).to.be.an.instanceof(iD.Relation);
- // expect(created[1]).to.be.an.instanceof(iD.Way);
- // expect(created[2]).to.be.an.instanceof(iD.Node);
- // expect(created[3]).to.be.an.instanceof(iD.Node);
- // });
-
- it("shallow copies from one graph to another", function () {
- var a = iD.Node({id: 'a'}),
- b = iD.Node({id: 'b'}),
- w = iD.Way({id: 'w', nodes: ['a', 'b']}),
- source = iD.Graph([a, b, w]),
- base = iD.Graph(),
- head = iD.actions.CopyEntity('w', source, false)(base),
- diff = iD.Difference(base, head),
- created = diff.created();
-
- expect(created).to.have.length(1);
- expect(created[0]).to.be.an.instanceof(iD.Way);
- });
-
- it("deep copies from one graph to another", function () {
- var a = iD.Node({id: 'a'}),
- b = iD.Node({id: 'b'}),
- w = iD.Way({id: 'w', nodes: ['a', 'b']}),
- source = iD.Graph([a, b, w]),
- base = iD.Graph(),
- head = iD.actions.CopyEntity('w', source, true)(base),
- diff = iD.Difference(base, head),
- created = diff.created();
-
- expect(created).to.have.length(3);
- expect(created[0]).to.be.an.instanceof(iD.Way);
- expect(created[1]).to.be.an.instanceof(iD.Node);
- expect(created[2]).to.be.an.instanceof(iD.Node);
- });
-});
diff --git a/test/spec/core/entity.js b/test/spec/core/entity.js
index 5a6e0aa79a..50012798f7 100644
--- a/test/spec/core/entity.js
+++ b/test/spec/core/entity.js
@@ -38,25 +38,43 @@ describe('iD.Entity', function () {
describe("#copy", function () {
it("returns a new Entity", function () {
- var a = iD.Entity(),
- result = a.copy();
- expect(result).to.have.length(1);
- expect(result[0]).to.be.an.instanceof(iD.Entity);
- expect(a).not.to.equal(result[0]);
+ var n = iD.Entity({id: 'n'}),
+ result = n.copy(null, {});
+ expect(result).to.be.an.instanceof(iD.Entity);
+ expect(result).not.to.equal(n);
+ });
+
+ it("adds the new Entity to input object", function () {
+ var n = iD.Entity({id: 'n'}),
+ copies = {},
+ result = n.copy(null, copies);
+ expect(Object.keys(copies)).to.have.length(1);
+ expect(copies.n).to.equal(result);
+ });
+
+ it("returns an existing copy in input object", function () {
+ var n = iD.Entity({id: 'n'}),
+ copies = {},
+ result1 = n.copy(null, copies),
+ result2 = n.copy(null, copies);
+ expect(Object.keys(copies)).to.have.length(1);
+ expect(result1).to.equal(result2);
});
it("resets 'id', 'user', and 'version' properties", function () {
- var a = iD.Entity({id: 'n1234', version: 10, user: 'bot-mode'}),
- b = a.copy()[0];
- expect(b.isNew()).to.be.ok;
- expect(b.version).to.be.undefined;
- expect(b.user).to.be.undefined;
+ var n = iD.Entity({id: 'n', version: 10, user: 'user'}),
+ copies = {};
+ n.copy(null, copies);
+ expect(copies.n.isNew()).to.be.ok;
+ expect(copies.n.version).to.be.undefined;
+ expect(copies.n.user).to.be.undefined;
});
it("copies tags", function () {
- var a = iD.Entity({id: 'n1234', version: 10, user: 'test', tags: {foo: 'foo'}}),
- b = a.copy()[0];
- expect(b.tags).to.deep.equal(a.tags);
+ var n = iD.Entity({id: 'n', tags: {foo: 'foo'}}),
+ copies = {};
+ n.copy(null, copies);
+ expect(copies.n.tags).to.equal(n.tags);
});
});
diff --git a/test/spec/core/relation.js b/test/spec/core/relation.js
index 119df2fa77..1d30f32b0a 100644
--- a/test/spec/core/relation.js
+++ b/test/spec/core/relation.js
@@ -28,48 +28,47 @@ describe('iD.Relation', function () {
describe("#copy", function () {
it("returns a new Relation", function () {
- var r1 = iD.Relation({id: 'r1'}),
- result = r1.copy(),
- r2 = result[0];
+ var r = iD.Relation({id: 'r'}),
+ result = r.copy(null, {});
- expect(result).to.have.length(1);
- expect(r2).to.be.an.instanceof(iD.Relation);
- expect(r1).not.to.equal(r2);
+ expect(result).to.be.an.instanceof(iD.Relation);
+ expect(result).not.to.equal(r);
});
- it("keeps same members when deep = false", function () {
- var a = iD.Node({id: 'a'}),
- b = iD.Node({id: 'b'}),
- c = iD.Node({id: 'c'}),
- w1 = iD.Way({id: 'w1', nodes: ['a','b','c','a']}),
- r1 = iD.Relation({id: 'r1', members: [{id: 'w1', role: 'outer'}]}),
- graph = iD.Graph([a, b, c, w1, r1]),
- result = r1.copy(),
- r1_copy = result[0];
+ it("adds the new Relation to input object", function () {
+ var r = iD.Relation({id: 'r'}),
+ copies = {},
+ result = r.copy(null, copies);
+ expect(Object.keys(copies)).to.have.length(1);
+ expect(copies.r).to.equal(result);
+ });
- expect(result).to.have.length(1);
- expect(r1.members).to.deep.equal(r1_copy.members);
+ it("returns an existing copy in input object", function () {
+ var r = iD.Relation({id: 'r'}),
+ copies = {},
+ result1 = r.copy(null, copies),
+ result2 = r.copy(null, copies);
+ expect(Object.keys(copies)).to.have.length(1);
+ expect(result1).to.equal(result2);
});
- it("makes new members when deep = true", function () {
+ it("deep copies members", function () {
var a = iD.Node({id: 'a'}),
b = iD.Node({id: 'b'}),
c = iD.Node({id: 'c'}),
- w1 = iD.Way({id: 'w1', nodes: ['a','b','c','a']}),
- r1 = iD.Relation({id: 'r1', members: [{id: 'w1', role: 'outer'}]}),
- graph = iD.Graph([a, b, c, w1, r1]),
- result = r1.copy(true, graph),
- r1_copy = result[0];
-
- expect(result).to.have.length(5);
- expect(result[0]).to.be.an.instanceof(iD.Relation);
- expect(result[1]).to.be.an.instanceof(iD.Way);
- expect(result[2]).to.be.an.instanceof(iD.Node);
- expect(result[3]).to.be.an.instanceof(iD.Node);
- expect(result[4]).to.be.an.instanceof(iD.Node);
+ w = iD.Way({id: 'w', nodes: ['a','b','c','a']}),
+ r = iD.Relation({id: 'r', members: [{id: 'w', role: 'outer'}]}),
+ graph = iD.Graph([a, b, c, w, r]),
+ copies = {}
+ result = r.copy(graph, copies);
- expect(r1_copy.members[0].id).not.to.equal(r1.members[0].id);
- expect(r1_copy.members[0].role).to.equal(r1.members[0].role);
+ expect(Object.keys(copies)).to.have.length(5);
+ expect(copies.w).to.be.an.instanceof(iD.Way);
+ expect(copies.a).to.be.an.instanceof(iD.Node);
+ expect(copies.b).to.be.an.instanceof(iD.Node);
+ expect(copies.c).to.be.an.instanceof(iD.Node);
+ expect(result.members[0].id).not.to.equal(r.members[0].id);
+ expect(result.members[0].role).to.equal(r.members[0].role);
});
it("deep copies non-tree relation graphs without duplicating children", function () {
@@ -77,48 +76,39 @@ describe('iD.Relation', function () {
r1 = iD.Relation({id: 'r1', members: [{id: 'r2'}, {id: 'w'}]}),
r2 = iD.Relation({id: 'r2', members: [{id: 'w'}]}),
graph = iD.Graph([w, r1, r2]),
- result = r1.copy(true, graph),
- r1_copy = result[0],
- r2_copy = result[1],
- w_copy = result[2];
-
- expect(result).to.have.length(3);
- expect(r1_copy).to.be.an.instanceof(iD.Relation);
- expect(r2_copy).to.be.an.instanceof(iD.Relation);
- expect(w_copy).to.be.an.instanceof(iD.Way);
-
- expect(r1_copy.members[0].id).to.equal(r2_copy.id);
- expect(r1_copy.members[1].id).to.equal(r2_copy.members[0].id);
- });
-
- it("deep copies cyclical relation graphs without issue"); //, function () {
- // var r1 = iD.Relation({id: 'r1', members: [{id: 'r2'}]}),
- // r2 = iD.Relation({id: 'r2', members: [{id: 'r1'}]}),
- // graph = iD.Graph([r1, r2]),
- // result = r1.copy(true, graph),
- // r1_copy = result[0],
- // r2_copy = result[1];
-
- // expect(result).to.have.length(2);
- // expect(r1_copy).to.be.an.instanceof(iD.Relation);
- // expect(r2_copy).to.be.an.instanceof(iD.Relation);
-
- // var msg = 'r1_copy = ' + JSON.stringify(r1_copy) +
- // 'r2_copy = ' + JSON.stringify(r2_copy);
- // expect(r1_copy.members[0].id).to.equal(r2_copy.id, msg);
- // expect(r2_copy.members[0].id).to.equal(r1_copy.id, msg);
- // });
-
- it("deep copies self-refrencing relations without issue"); //, function () {
- // var r1 = iD.Relation({id: 'r1', members: [{id: 'r1'}]}),
- // graph = iD.Graph([r1]),
- // result = r1.copy(true, graph),
- // r1_copy = result[0];
-
- // expect(result).to.have.length(1);
- // expect(r1_copy).to.be.an.instanceof(iD.Relation);
- // expect(r1_copy.members[0].id).to.equal(r1_copy.id);
- // });
+ copies = {};
+ r1.copy(graph, copies);
+
+ expect(Object.keys(copies)).to.have.length(3);
+ expect(copies.r1).to.be.an.instanceof(iD.Relation);
+ expect(copies.r2).to.be.an.instanceof(iD.Relation);
+ expect(copies.w).to.be.an.instanceof(iD.Way);
+ expect(copies.r1.members[0].id).to.equal(copies.r2.id);
+ expect(copies.r1.members[1].id).to.equal(copies.w.id);
+ expect(copies.r2.members[0].id).to.equal(copies.w.id);
+ });
+
+ it("deep copies cyclical relation graphs without issue", function () {
+ var r1 = iD.Relation({id: 'r1', members: [{id: 'r2'}]}),
+ r2 = iD.Relation({id: 'r2', members: [{id: 'r1'}]}),
+ graph = iD.Graph([r1, r2]),
+ copies = {};
+ r1.copy(graph, copies);
+
+ expect(Object.keys(copies)).to.have.length(2);
+ expect(copies.r1.members[0].id).to.equal(copies.r2.id);
+ expect(copies.r2.members[0].id).to.equal(copies.r1.id);
+ });
+
+ it("deep copies self-referencing relations without issue", function () {
+ var r = iD.Relation({id: 'r', members: [{id: 'r'}]}),
+ graph = iD.Graph([r]),
+ copies = {};
+ r.copy(graph, copies);
+
+ expect(Object.keys(copies)).to.have.length(1);
+ expect(copies.r.members[0].id).to.equal(copies.r.id);
+ });
});
describe("#extent", function () {
diff --git a/test/spec/core/way.js b/test/spec/core/way.js
index 0034548049..93fd66e158 100644
--- a/test/spec/core/way.js
+++ b/test/spec/core/way.js
@@ -28,47 +28,54 @@ describe('iD.Way', function() {
describe("#copy", function () {
it("returns a new Way", function () {
- var w1 = iD.Way({id: 'w1'}),
- result = w1.copy(),
- w2 = result[0];
+ var w = iD.Way({id: 'w'}),
+ result = w.copy(null, {});
- expect(result).to.have.length(1);
- expect(w2).to.be.an.instanceof(iD.Way);
- expect(w1).not.to.equal(w2);
+ expect(result).to.be.an.instanceof(iD.Way);
+ expect(result).not.to.equal(w);
});
- it("keeps same nodes when deep = false", function () {
+ it("adds the new Way to input object", function () {
+ var w = iD.Way({id: 'w'}),
+ copies = {},
+ result = w.copy(null, copies);
+ expect(Object.keys(copies)).to.have.length(1);
+ expect(copies.w).to.equal(result);
+ });
+
+ it("returns an existing copy in input object", function () {
+ var w = iD.Way({id: 'w'}),
+ copies = {},
+ result1 = w.copy(null, copies),
+ result2 = w.copy(null, copies);
+ expect(Object.keys(copies)).to.have.length(1);
+ expect(result1).to.equal(result2);
+ });
+
+ it("deep copies nodes", function () {
var a = iD.Node({id: 'a'}),
b = iD.Node({id: 'b'}),
- c = iD.Node({id: 'c'}),
- w1 = iD.Way({id: 'w1', nodes: ['a','b','c','a']}),
- graph = iD.Graph([a, b, c, w1]),
- result = w1.copy(),
- w2 = result[0];
+ w = iD.Way({id: 'w', nodes: ['a', 'b']}),
+ graph = iD.Graph([a, b, w]),
+ copies = {},
+ result = w.copy(graph, copies);
- expect(result).to.have.length(1);
- expect(w1.nodes).to.deep.equal(w2.nodes);
+ expect(Object.keys(copies)).to.have.length(3);
+ expect(copies.a).to.be.an.instanceof(iD.Node);
+ expect(copies.b).to.be.an.instanceof(iD.Node);
+ expect(copies.a).not.to.equal(w.nodes[0]);
+ expect(copies.b).not.to.equal(w.nodes[1]);
+ expect(result.nodes).to.deep.eql([copies.a.id, copies.b.id]);
});
- it("makes new nodes when deep = true", function () {
+ it("creates only one copy of shared nodes", function () {
var a = iD.Node({id: 'a'}),
- b = iD.Node({id: 'b'}),
- c = iD.Node({id: 'c'}),
- w1 = iD.Way({id: 'w1', nodes: ['a','b','c','a']}),
- graph = iD.Graph([a, b, c, w1]),
- result = w1.copy(true, graph),
- w2 = result[0];
-
- expect(result).to.have.length(4);
- expect(result[0]).to.be.an.instanceof(iD.Way);
- expect(result[1]).to.be.an.instanceof(iD.Node);
- expect(result[2]).to.be.an.instanceof(iD.Node);
- expect(result[3]).to.be.an.instanceof(iD.Node);
-
- expect(w2.nodes[0]).not.to.equal(w1.nodes[0]);
- expect(w2.nodes[1]).not.to.equal(w1.nodes[1]);
- expect(w2.nodes[2]).not.to.equal(w1.nodes[2]);
- expect(w2.nodes[3]).to.equal(w2.nodes[0]);
+ w = iD.Way({id: 'w', nodes: ['a', 'a']}),
+ graph = iD.Graph([a, w]),
+ copies = {},
+ result = w.copy(graph, copies);
+
+ expect(result.nodes[0]).to.equal(result.nodes[1]);
});
});