Files
iD/test/spec/core/tree.js
John Firebaugh ffdeef398d Rewrite tree logic
The main problem with the existing logic was that it
did not update the extents of relations when previously incomplete members were loaded.

It was also overly stateful; the various queues and flags
are no longer required.

Fixes #1928.
Fixes #1540.
2013-10-28 16:57:18 -07:00

166 lines
6.3 KiB
JavaScript

describe("iD.Tree", function() {
describe("#rebase", function() {
it("adds entities to the tree", function() {
var graph = iD.Graph(),
tree = iD.Tree(graph),
node = iD.Node({id: 'n', loc: [1, 1]});
graph.rebase({n: node});
tree.rebase([node]);
expect(tree.intersects(iD.geo.Extent([0, 0], [2, 2]), graph)).to.eql([node]);
});
it("is idempotent", function() {
var graph = iD.Graph(),
tree = iD.Tree(graph),
node = iD.Node({id: 'n', loc: [1, 1]}),
extent = iD.geo.Extent([0, 0], [2, 2]);
graph.rebase({n: node});
tree.rebase([node]);
expect(tree.intersects(extent, graph)).to.eql([node]);
graph.rebase({n: node});
tree.rebase([node]);
expect(tree.intersects(extent, graph)).to.eql([node]);
});
it("does not insert if entity has a modified version", function() {
var graph = iD.Graph(),
tree = iD.Tree(graph),
node = iD.Node({id: 'n', loc: [1, 1]}),
node_ = node.update({loc: [10, 10]}),
g = graph.replace(node_);
expect(tree.intersects(iD.geo.Extent([9, 9], [11, 11]), g)).to.eql([node_]);
graph.rebase({n: node});
tree.rebase([node]);
expect(tree.intersects(iD.geo.Extent([0, 0], [2, 2]), g)).to.eql([]);
expect(tree.intersects(iD.geo.Extent([0, 0], [11, 11]), g)).to.eql([node_]);
});
});
describe("#intersects", function() {
it("includes entities within extent, excludes those without", function() {
var graph = iD.Graph(),
tree = iD.Tree(graph),
n1 = iD.Node({loc: [1, 1]}),
n2 = iD.Node({loc: [3, 3]}),
extent = iD.geo.Extent([0, 0], [2, 2]);
graph = graph.replace(n1).replace(n2);
expect(tree.intersects(extent, graph)).to.eql([n1]);
});
it("includes intersecting relations after incomplete members are loaded", function() {
var graph = iD.Graph(),
tree = iD.Tree(graph),
n1 = iD.Node({id: 'n1', loc: [0, 0]}),
n2 = iD.Node({id: 'n2', loc: [1, 1]}),
relation = iD.Relation({id: 'r', members: [{id: 'n1'}, {id: 'n2'}]}),
extent = iD.geo.Extent([0.5, 0.5], [1.5, 1.5]);
graph.rebase({r: relation, n1: n1});
tree.rebase([relation, n1]);
expect(tree.intersects(extent, graph)).to.eql([]);
graph.rebase({n2: n2});
tree.rebase([n2]);
expect(tree.intersects(extent, graph)).to.eql([n2, relation]);
});
// This happens when local storage includes a changed way but not its nodes.
it("includes intersecting ways after missing nodes are loaded", function() {
var base = iD.Graph(),
tree = iD.Tree(base),
node = iD.Node({id: 'n', loc: [0.5, 0.5]}),
way = iD.Way({nodes: ['n']}),
graph = base.replace(way),
extent = iD.geo.Extent([0, 0], [1, 1]);
expect(tree.intersects(extent, graph)).to.eql([]);
base.rebase({n: node});
graph.rebase({n: node});
tree.rebase([node]);
expect(tree.intersects(extent, graph)).to.eql([node, way]);
});
it("adjusts parent ways when a member node is moved", function() {
var graph = iD.Graph(),
tree = iD.Tree(graph),
node = iD.Node({id: 'n', loc: [1, 1]}),
way = iD.Way({nodes: ['n']}),
extent = iD.geo.Extent([0, 0], [2, 2]);
graph = graph.replace(node).replace(way);
expect(tree.intersects(extent, graph)).to.eql([node, way]);
graph = graph.replace(node.move([3, 3]));
expect(tree.intersects(extent, graph)).to.eql([]);
});
it("adjusts parent ways when a member node is removed", function() {
var graph = iD.Graph(),
tree = iD.Tree(graph),
n1 = iD.Node({id: 'n1', loc: [1, 1]}),
n2 = iD.Node({id: 'n2', loc: [3, 3]}),
way = iD.Way({nodes: ['n1', 'n2']}),
extent = iD.geo.Extent([0, 0], [2, 2]);
graph = graph.replace(n1).replace(n2).replace(way);
expect(tree.intersects(extent, graph)).to.eql([n1, way]);
graph = graph.replace(way.removeNode('n1'));
expect(tree.intersects(extent, graph)).to.eql([n1]);
});
it("doesn't include removed entities", function() {
var graph = iD.Graph(),
tree = iD.Tree(graph),
node = iD.Node({loc: [1, 1]}),
extent = iD.geo.Extent([0, 0], [2, 2]);
graph = graph.replace(node);
expect(tree.intersects(extent, graph)).to.eql([node]);
graph = graph.remove(node);
expect(tree.intersects(extent, graph)).to.eql([]);
});
it("doesn't include removed entities after rebase", function() {
var base = iD.Graph(),
tree = iD.Tree(base),
node = iD.Node({id: 'n', loc: [1, 1]}),
extent = iD.geo.Extent([0, 0], [2, 2]);
var graph = base.replace(node).remove(node);
expect(tree.intersects(extent, graph)).to.eql([]);
base.rebase({n: node});
tree.rebase([node]);
expect(tree.intersects(extent, graph)).to.eql([]);
});
it("handles recursive relations", function() {
var base = iD.Graph(),
tree = iD.Tree(base),
node = iD.Node({id: 'n', loc: [1, 1]}),
r1 = iD.Relation({id: 'r1', members: [{id: 'n'}]}),
r2 = iD.Relation({id: 'r2', members: [{id: 'r1'}]}),
extent = iD.geo.Extent([0, 0], [2, 2]);
var graph = base.replace(r1).replace(r2);
expect(tree.intersects(extent, graph)).to.eql([]);
base.rebase({n: node});
graph.rebase({n: node});
tree.rebase([node]);
expect(tree.intersects(extent, graph)).to.eql([node, r1, r2]);
});
});
});