Files
iD/test/spec/actions/connect.js
2021-12-06 21:23:38 +01:00

518 lines
21 KiB
JavaScript

describe('iD.actionConnect', function() {
it('merges tags', function() {
var graph = iD.coreGraph([
iD.osmNode({id: 'a', tags: { highway: 'traffic_signals' }}),
iD.osmNode({id: 'b', tags: { crossing: 'marked' }}),
]);
graph = iD.actionConnect(['a', 'b'])(graph);
expect(graph.hasEntity('a')).not.to.be.ok;
var survivor = graph.hasEntity('b');
expect(survivor).to.be.an.instanceof(iD.osmNode);
expect(survivor.tags).to.eql({ highway: 'traffic_signals', crossing: 'marked' }, 'merge all tags');
});
it('chooses the oldest node as the survivor', function() {
var graph = iD.coreGraph([
iD.osmNode({id: 'n3'}),
iD.osmNode({id: 'n-1'}),
iD.osmNode({id: 'n2'}),
iD.osmNode({id: 'n4'})
]);
graph = iD.actionConnect(['n3', 'n-1', 'n2', 'n4'])(graph);
expect(graph.hasEntity('n3')).not.to.be.ok;
expect(graph.hasEntity('n-1')).not.to.be.ok;
expect(graph.hasEntity('n2')).to.be.ok;
expect(graph.hasEntity('n4')).not.to.be.ok;
});
it('chooses the oldest interesting node as the survivor', function() {
var graph = iD.coreGraph([
iD.osmNode({id: 'n3'}),
iD.osmNode({id: 'n1'}),
iD.osmNode({id: 'n2', tags: { highway: 'traffic_signals' }}),
iD.osmNode({id: 'n4', tags: { crossing: 'marked' }})
]);
graph = iD.actionConnect(['n3', 'n1', 'n2', 'n4'])(graph);
expect(graph.hasEntity('n3')).not.to.be.ok;
expect(graph.hasEntity('n1')).not.to.be.ok;
expect(graph.hasEntity('n4')).not.to.be.ok;
var survivor = graph.hasEntity('n2');
expect(survivor).to.be.an.instanceof(iD.osmNode);
expect(survivor.tags).to.eql({ highway: 'traffic_signals', crossing: 'marked' }, 'merge all tags');
});
it('chooses an existing node as the survivor', function() {
var graph = iD.coreGraph([
iD.osmNode({id: 'n3'}),
iD.osmNode({id: 'n-1'}),
iD.osmNode({id: 'n-2', tags: { highway: 'traffic_signals' }}),
iD.osmNode({id: 'n-4', tags: { crossing: 'marked' }})
]);
graph = iD.actionConnect(['n3', 'n-1', 'n-2', 'n-4'])(graph);
expect(graph.hasEntity('n-1')).not.to.be.ok;
expect(graph.hasEntity('n-2')).not.to.be.ok;
expect(graph.hasEntity('n-4')).not.to.be.ok;
var survivor = graph.hasEntity('n3');
expect(survivor).to.be.an.instanceof(iD.osmNode);
expect(survivor.tags).to.eql({ highway: 'traffic_signals', crossing: 'marked' }, 'merge all tags');
});
it('chooses the last node as the survivor when all are new', function() {
var graph = iD.coreGraph([
iD.osmNode({id: 'a', tags: { highway: 'traffic_signals' }}),
iD.osmNode({id: 'b', tags: { crossing: 'marked' }}),
iD.osmNode({id: 'c'})
]);
graph = iD.actionConnect(['a', 'b', 'c'])(graph);
expect(graph.hasEntity('a')).not.to.be.ok;
expect(graph.hasEntity('b')).not.to.be.ok;
var survivor = graph.hasEntity('c');
expect(survivor).to.be.an.instanceof(iD.osmNode);
expect(survivor.tags).to.eql({ highway: 'traffic_signals', crossing: 'marked' }, 'merge all tags');
});
it('replaces non-surviving nodes in parent ways', function() {
// a --- b --- c
//
// e
// |
// d
//
// Connect [e, b].
//
// Expected result:
//
// a --- b --- c
// |
// d
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'd'}),
iD.osmNode({id: 'e'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']}),
iD.osmWay({id: '|', nodes: ['d', 'e']})
]);
graph = iD.actionConnect(['e', 'b'])(graph);
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'c']);
expect(graph.entity('|').nodes).to.eql(['d', 'b']);
});
it('handles circular ways', function() {
// c -- a d === e
// | /
// | /
// | /
// b
//
// Connect [a, d].
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'd'}),
iD.osmNode({id: 'e'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c', 'a']}),
iD.osmWay({id: '=', nodes: ['d', 'e']})
]);
graph = iD.actionConnect(['a', 'd'])(graph);
expect(graph.entity('-').nodes).to.eql(['d', 'b', 'c', 'd']);
});
it('merges adjacent nodes', function() {
// a --- b --- c
//
// Connect [b, c]
//
// Expected result:
//
// a --- c
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']})
]);
graph = iD.actionConnect(['b', 'c'])(graph);
expect(graph.entity('-').nodes).to.eql(['a', 'c']);
expect(graph.hasEntity('b')).to.be.undefined;
});
it('merges adjacent nodes with connections', function() {
// a --- b --- c
// |
// d
//
// Connect [b, c]
//
// Expected result:
//
// a --- c
// |
// d
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'c'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']}),
iD.osmWay({id: '|', nodes: ['b', 'd']})
]);
graph = iD.actionConnect(['b', 'c'])(graph);
expect(graph.entity('-').nodes).to.eql(['a', 'c']);
expect(graph.entity('|').nodes).to.eql(['c', 'd']);
expect(graph.hasEntity('b')).to.be.undefined;
});
it('deletes a degenerate way', function() {
// a --- b
//
// Connect [a, b]
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmWay({id: '-', nodes: ['a', 'b']})
]);
graph = iD.actionConnect(['a', 'b'])(graph);
expect(graph.hasEntity('a')).to.be.undefined;
expect(graph.hasEntity('-')).to.be.undefined;
});
it('merges tags to the surviving node', function() {
var graph = iD.coreGraph([
iD.osmNode({id: 'a', tags: {a: 'a'}}),
iD.osmNode({id: 'b', tags: {b: 'b'}}),
iD.osmNode({id: 'c', tags: {c: 'c'}})
]);
graph = iD.actionConnect(['a', 'b', 'c'])(graph);
expect(graph.entity('c').tags).to.eql({a: 'a', b: 'b', c: 'c'});
});
it('merges memberships to the surviving node', function() {
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'c'}),
iD.osmWay({id: '-', nodes: ['a', 'b']}),
iD.osmWay({id: '=', nodes: ['c', 'd']}),
iD.osmRelation({id: 'r1', members: [{id: 'b', role: 'r1', type: 'node'}]}),
iD.osmRelation({id: 'r2', members: [{id: 'b', role: 'r2', type: 'node'}, {id: 'c', role: 'r2', type: 'node'}]})
]);
graph = iD.actionConnect(['b', 'c'])(graph);
expect(graph.entity('r1').members).to.eql([{id: 'c', role: 'r1', type: 'node'}]);
expect(graph.entity('r2').members).to.eql([{id: 'c', role: 'r2', type: 'node'}]);
});
describe('#disabled', function () {
it('returns falsy when connecting members of the same relation and same roles', function () {
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']}),
iD.osmRelation({id: 'r1', members: [
{ id: 'b', type: 'node', role: 'foo' },
{ id: 'c', type: 'node', role: 'foo' }
]})
]);
expect(iD.actionConnect(['b', 'c']).disabled(graph)).to.be.not.ok;
});
it('returns falsy when connecting members of different relation and different roles', function () {
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']}),
iD.osmRelation({id: 'r1', members: [{ id: 'b', type: 'node', role: 'foo' } ]}),
iD.osmRelation({id: 'r2', members: [{ id: 'c', type: 'node', role: 'bar' } ]})
]);
expect(iD.actionConnect(['b', 'c']).disabled(graph)).to.be.not.ok;
});
it('returns \'relation\' when connecting members of the same relation but different roles', function () {
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']}),
iD.osmRelation({id: 'r1', members: [
{ id: 'b', type: 'node', role: 'foo' },
{ id: 'c', type: 'node', role: 'bar' }
]})
]);
expect(iD.actionConnect(['b', 'c']).disabled(graph)).to.eql('relation');
});
it('returns falsy when connecting a node unrelated to the restriction', function () {
//
// a --- b d ~~~ e r1: `no_right_turn`
// | FROM '-'
// | VIA 'b'
// c TO '|'
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'd'}),
iD.osmNode({id: 'e'}),
iD.osmWay({id: '-', nodes: ['a', 'b']}),
iD.osmWay({id: '|', nodes: ['b', 'c']}),
iD.osmWay({id: '~', nodes: ['d', 'e']}),
iD.osmRelation({id: 'r1', tags: { type: 'restriction', restriction: 'no_right_turn' }, members: [
{ id: '-', type: 'way', role: 'from' },
{ id: 'b', type: 'node', role: 'via' },
{ id: '|', type: 'way', role: 'to' }
]})
]);
expect(iD.actionConnect(['a', 'd']).disabled(graph)).to.be.not.ok;
expect(iD.actionConnect(['b', 'd']).disabled(graph)).to.be.not.ok;
expect(iD.actionConnect(['c', 'd']).disabled(graph)).to.be.not.ok;
});
it('returns falsy when connecting nodes that would not break a via-node restriction', function () {
//
// a --- b --- c r1: `no_right_turn`
// | FROM '-'
// d VIA 'c'
// | TO '|'
// e
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'd'}),
iD.osmNode({id: 'e'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']}),
iD.osmWay({id: '|', nodes: ['c', 'd', 'e']}),
iD.osmRelation({id: 'r1', tags: { type: 'restriction', restriction: 'no_right_turn' }, members: [
{ id: '-', type: 'way', role: 'from' },
{ id: 'c', type: 'node', role: 'via' },
{ id: '|', type: 'way', role: 'to' }
]})
]);
// allowed: adjacent connections that don't destroy a way
expect(iD.actionConnect(['a', 'b']).disabled(graph)).to.be.not.ok;
expect(iD.actionConnect(['b', 'c']).disabled(graph)).to.be.not.ok;
expect(iD.actionConnect(['c', 'd']).disabled(graph)).to.be.not.ok;
expect(iD.actionConnect(['d', 'e']).disabled(graph)).to.be.not.ok;
});
it('returns falsy when connecting nodes that would not break a via-way restriction', function () {
//
// a --- b --- c r1: `no_u_turn`
// | FROM '='
// d VIA '|'
// | TO '-'
// g === f === e
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'd'}),
iD.osmNode({id: 'e'}),
iD.osmNode({id: 'f'}),
iD.osmNode({id: 'g'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']}),
iD.osmWay({id: '|', nodes: ['c', 'd', 'e']}),
iD.osmWay({id: '=', nodes: ['e', 'f', 'g']}),
iD.osmRelation({id: 'r1', tags: { type: 'restriction', restriction: 'no_u_turn' }, members: [
{ id: '=', type: 'way', role: 'from' },
{ id: '|', type: 'way', role: 'via' },
{ id: '-', type: 'way', role: 'to' }
]})
]);
// allowed: adjacent connections that don't destroy a way
expect(iD.actionConnect(['a', 'b']).disabled(graph)).to.be.not.ok;
expect(iD.actionConnect(['b', 'c']).disabled(graph)).to.be.not.ok;
expect(iD.actionConnect(['c', 'd']).disabled(graph)).to.be.not.ok;
expect(iD.actionConnect(['d', 'e']).disabled(graph)).to.be.not.ok;
expect(iD.actionConnect(['e', 'f']).disabled(graph)).to.be.not.ok;
expect(iD.actionConnect(['f', 'g']).disabled(graph)).to.be.not.ok;
});
it('returns \'restriction\' when connecting nodes that would break a via-node restriction', function () {
//
// a --- b --- c r1: `no_right_turn`
// | FROM '-'
// d VIA 'c'
// | TO '|'
// e
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'd'}),
iD.osmNode({id: 'e'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']}),
iD.osmWay({id: '|', nodes: ['c', 'd', 'e']}),
iD.osmRelation({id: 'r1', tags: { type: 'restriction', restriction: 'no_right_turn' }, members: [
{ id: '-', type: 'way', role: 'from' },
{ id: 'c', type: 'node', role: 'via' },
{ id: '|', type: 'way', role: 'to' }
]})
]);
// prevented:
// extra connections to the VIA node, or any connections between distinct FROM and TO
expect(iD.actionConnect(['a', 'c']).disabled(graph)).to.eql('restriction', 'extra connection FROM-VIA');
expect(iD.actionConnect(['e', 'c']).disabled(graph)).to.eql('restriction', 'extra connection TO-VIA');
expect(iD.actionConnect(['b', 'd']).disabled(graph)).to.eql('restriction', 'extra connection FROM-TO');
});
it('returns falsy when connecting nodes on a via-node u_turn restriction', function () {
//
// a --- b --- c r1: `no_u_turn`
// | FROM '-'
// d VIA 'c'
// | TO '-'
// e
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'd'}),
iD.osmNode({id: 'e'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']}),
iD.osmWay({id: '|', nodes: ['c', 'd', 'e']}),
iD.osmRelation({id: 'r1', tags: { type: 'restriction', restriction: 'no_u_turn' }, members: [
{ id: '-', type: 'way', role: 'from' },
{ id: 'c', type: 'node', role: 'via' },
{ id: '-', type: 'way', role: 'to' }
]})
]);
// The u-turn case is one where a connection between FROM-TO should be allowed
expect(iD.actionConnect(['a', 'b']).disabled(graph)).to.be.not.ok;
expect(iD.actionConnect(['b', 'c']).disabled(graph)).to.be.not.ok;
});
it('returns \'restriction\' when connecting nodes that would break a via-way restriction', function () {
//
// a --- b --- c r1: `no_u_turn`
// | FROM '='
// d VIA '|'
// | TO '-'
// g === f === e
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'd'}),
iD.osmNode({id: 'e'}),
iD.osmNode({id: 'f'}),
iD.osmNode({id: 'g'}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c']}),
iD.osmWay({id: '|', nodes: ['c', 'd', 'e']}),
iD.osmWay({id: '=', nodes: ['e', 'f', 'g']}),
iD.osmRelation({id: 'r1', tags: { type: 'restriction', restriction: 'no_u_turn' }, members: [
{ id: '=', type: 'way', role: 'from' },
{ id: '|', type: 'way', role: 'via' },
{ id: '-', type: 'way', role: 'to' }
]})
]);
// prevented:
// extra connections to any node along VIA way
expect(iD.actionConnect(['a', 'c']).disabled(graph)).to.eql('restriction', 'extra connection TO-VIA c');
expect(iD.actionConnect(['b', 'd']).disabled(graph)).to.eql('restriction', 'extra connection TO-VIA d');
expect(iD.actionConnect(['b', 'e']).disabled(graph)).to.eql('restriction', 'extra connection TO-VIA e');
expect(iD.actionConnect(['c', 'e']).disabled(graph)).to.eql('restriction', 'extra connection VIA-VIA');
expect(iD.actionConnect(['f', 'c']).disabled(graph)).to.eql('restriction', 'extra connection FROM-VIA c');
expect(iD.actionConnect(['f', 'd']).disabled(graph)).to.eql('restriction', 'extra connection FROM-VIA d');
expect(iD.actionConnect(['g', 'e']).disabled(graph)).to.eql('restriction', 'extra connection FROM-VIA e');
});
it('returns \'restriction\' when connecting would destroy a way in a via-node restriction', function () {
//
// a --- b r1: `no_right_turn`
// | FROM '-'
// | VIA 'b'
// c TO '|'
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmWay({id: '-', nodes: ['a', 'b']}),
iD.osmWay({id: '|', nodes: ['b', 'c']}),
iD.osmRelation({id: 'r1', tags: { type: 'restriction', restriction: 'no_right_turn' }, members: [
{ id: '-', type: 'way', role: 'from' },
{ id: 'b', type: 'node', role: 'via' },
{ id: '|', type: 'way', role: 'to' }
]})
]);
expect(iD.actionConnect(['a', 'b']).disabled(graph)).to.eql('restriction', 'destroy FROM');
expect(iD.actionConnect(['b', 'c']).disabled(graph)).to.eql('restriction', 'destroy TO');
});
it('returns \'restriction\' when connecting would destroy a way in via-way restriction', function () {
//
// a --- b r1: `no_u_turn`
// | FROM '='
// | VIA '|'
// d === c TO '-'
//
var graph = iD.coreGraph([
iD.osmNode({id: 'a'}),
iD.osmNode({id: 'b'}),
iD.osmNode({id: 'c'}),
iD.osmNode({id: 'd'}),
iD.osmWay({id: '-', nodes: ['a', 'b']}),
iD.osmWay({id: '|', nodes: ['b', 'c']}),
iD.osmWay({id: '=', nodes: ['c', 'd']}),
iD.osmRelation({id: 'r1', tags: { type: 'restriction', restriction: 'no_u_turn' }, members: [
{ id: '=', type: 'way', role: 'from' },
{ id: '|', type: 'way', role: 'via' },
{ id: '-', type: 'way', role: 'to' }
]})
]);
expect(iD.actionConnect(['a', 'b']).disabled(graph)).to.eql('restriction', 'destroy TO');
expect(iD.actionConnect(['b', 'c']).disabled(graph)).to.eql('restriction', 'destroy VIA');
expect(iD.actionConnect(['c', 'd']).disabled(graph)).to.eql('restriction', 'destroy FROM');
});
});
});