fix false positive "unreachable oneway" validation cased by oneway=-1

fixes #11068
This commit is contained in:
Martin Raifer
2025-05-27 14:43:37 +02:00
parent ca98ef6f1f
commit bd71ccba17
3 changed files with 216 additions and 30 deletions

View File

@@ -0,0 +1,187 @@
describe('iD.validations.impossible_oneway', function() {
let context;
beforeEach(function() {
context = iD.coreContext().assetPath('../dist/').init();
iD.services.osm = { isDataLoaded: () => true };
});
function validate() {
const validator = iD.validationImpossibleOneway(context);
const changes = context.history().changes();
const entities = changes.modified.concat(changes.created);
const issues = entities.flatMap(entity =>
validator(entity, context.graph()));
return issues;
}
it('has no errors on init', function() {
var issues = validate();
expect(issues).to.have.lengthOf(0);
});
describe('highways', function() {
it('does not flag properly connecting oneway roads', function() {
context.perform(...[
iD.osmNode({ id: 'n-0', loc: [2, 1] }),
iD.osmNode({ id: 'n-1', loc: [1, 0] }),
iD.osmNode({ id: 'n-2', loc: [2, 0] }),
iD.osmNode({ id: 'n-3', loc: [3, 0] }),
iD.osmWay({ id: 'w-0', nodes: ['n-1', 'n-0', 'n-3'], tags: {
'highway': 'unclassified'
}}),
iD.osmWay({ id: 'w-1', nodes: ['n-1', 'n-2'], tags: {
'highway': 'unclassified',
'oneway' : 'yes'
}}),
iD.osmWay({ id: 'w-2', nodes: ['n-2', 'n-3'], tags: {
'highway': 'unclassified',
'oneway' : 'yes'
}})
].map(iD.actionAddEntity));
const issues = validate();
expect(issues).to.have.lengthOf(0);
});
it('flags dangling oneway end', function() {
context.perform(...[
iD.osmNode({ id: 'n-0', loc: [0, 0] }),
iD.osmNode({ id: 'n-1', loc: [1, 0] }),
iD.osmNode({ id: 'n-2', loc: [2, 0] }),
iD.osmWay({ id: 'w-0', nodes: ['n-0', 'n-1'], tags: {
'highway': 'unclassified'
}}),
iD.osmWay({ id: 'w-1', nodes: ['n-1', 'n-2'], tags: {
'highway': 'unclassified',
'oneway' : 'yes'
}})
].map(iD.actionAddEntity));
const issues = validate();
expect(issues).to.have.lengthOf(1);
const issue1 = issues[0];
expect(issue1.type).to.eql('impossible_oneway');
expect(issue1.subtype).to.eql('highway');
expect(issue1.severity).to.eql('warning');
expect(issue1.entityIds).to.eql(['w-1', 'n-2']);
});
it('flags unconnected oneway start', function() {
context.perform(...[
iD.osmNode({ id: 'n-0', loc: [0, 0] }),
iD.osmNode({ id: 'n-1', loc: [1, 0] }),
iD.osmNode({ id: 'n-2', loc: [2, 0] }),
iD.osmWay({ id: 'w-0', nodes: ['n-0', 'n-1'], tags: {
'highway': 'unclassified'
}}),
iD.osmWay({ id: 'w-1', nodes: ['n-2', 'n-1'], tags: {
'highway': 'unclassified',
'oneway' : 'yes'
}})
].map(iD.actionAddEntity));
const issues = validate();
expect(issues).to.have.lengthOf(1);
const issue1 = issues[0];
expect(issue1.type).to.eql('impossible_oneway');
expect(issue1.subtype).to.eql('highway');
expect(issue1.severity).to.eql('warning');
expect(issue1.entityIds).to.eql(['w-1', 'n-2']);
});
it('flags oneway pointing to each other', function() {
context.perform(...[
iD.osmNode({ id: 'n-0', loc: [2, 1] }),
iD.osmNode({ id: 'n-1', loc: [1, 0] }),
iD.osmNode({ id: 'n-2', loc: [2, 0] }),
iD.osmNode({ id: 'n-3', loc: [3, 0] }),
iD.osmWay({ id: 'w-0', nodes: ['n-1', 'n-0', 'n-3'], tags: {
'highway': 'unclassified'
}}),
iD.osmWay({ id: 'w-1', nodes: ['n-1', 'n-2'], tags: {
'highway': 'unclassified',
'oneway' : 'yes'
}}),
iD.osmWay({ id: 'w-2', nodes: ['n-3', 'n-2'], tags: {
'highway': 'unclassified',
'oneway' : 'yes'
}})
].map(iD.actionAddEntity));
const issues = validate();
expect(issues).to.have.lengthOf(2);
const issue1 = issues[0];
expect(issue1.type).to.eql('impossible_oneway');
expect(issue1.subtype).to.eql('highway');
expect(issue1.severity).to.eql('warning');
expect(issue1.entityIds).to.eql(['w-1', 'n-2']);
const issue2 = issues[1];
expect(issue2.type).to.eql('impossible_oneway');
expect(issue2.entityIds).to.eql(['w-2', 'n-2']);
});
it('does not flags oneway with reverse "-1" oneway direction', function() {
context.perform(...[
iD.osmNode({ id: 'n-0', loc: [2, 1] }),
iD.osmNode({ id: 'n-1', loc: [1, 0] }),
iD.osmNode({ id: 'n-2', loc: [2, 0] }),
iD.osmNode({ id: 'n-3', loc: [3, 0] }),
iD.osmWay({ id: 'w-0', nodes: ['n-1', 'n-0', 'n-3'], tags: {
'highway': 'unclassified'
}}),
iD.osmWay({ id: 'w-1', nodes: ['n-1', 'n-2'], tags: {
'highway': 'unclassified',
'oneway' : 'yes'
}}),
iD.osmWay({ id: 'w-2', nodes: ['n-3', 'n-2'], tags: {
'highway': 'unclassified',
'oneway' : '-1'
}})
].map(iD.actionAddEntity));
const issues = validate();
expect(issues).to.have.lengthOf(0);
});
});
describe('waterways', function() {
it('does not flag unconnected start or end points', function() {
context.perform(...[
iD.osmNode({ id: 'n-1', loc: [1, 0] }),
iD.osmNode({ id: 'n-2', loc: [2, 0] }),
iD.osmWay({ id: 'w-1', nodes: ['n-1', 'n-2'], tags: {
'waterway': 'stream'
}})
].map(iD.actionAddEntity));
const issues = validate();
expect(issues).to.have.lengthOf(0);
});
it('flags waterways pointing to each other', function() {
context.perform(...[
iD.osmNode({ id: 'n-1', loc: [1, 0] }),
iD.osmNode({ id: 'n-2', loc: [2, 0] }),
iD.osmNode({ id: 'n-3', loc: [3, 0] }),
iD.osmWay({ id: 'w-1', nodes: ['n-1', 'n-2'], tags: {
'waterway': 'stream'
}}),
iD.osmWay({ id: 'w-2', nodes: ['n-3', 'n-2'], tags: {
'waterway': 'stream'
}})
].map(iD.actionAddEntity));
const issues = validate();
expect(issues).to.have.lengthOf(2);
const issue1 = issues[0];
expect(issue1.type).to.eql('impossible_oneway');
expect(issue1.subtype).to.eql('waterway');
expect(issue1.severity).to.eql('warning');
expect(issue1.entityIds).to.eql(['w-1', 'n-2']);
const issue2 = issues[1];
expect(issue2.type).to.eql('impossible_oneway');
expect(issue2.entityIds).to.eql(['w-2', 'n-2']);
});
});
});