mirror of
https://github.com/FoggedLens/iD.git
synced 2026-03-22 19:13:35 +00:00
357 lines
18 KiB
JavaScript
357 lines
18 KiB
JavaScript
describe('iD.utilMapCSSRule', function() {
|
|
var entities = [
|
|
iD.Entity({ type: 'node', tags: { amenity: 'marketplace' }}),
|
|
iD.Entity({ type: 'node', tags: { man_made: 'water_tap' }}),
|
|
iD.Entity({ type: 'node', tags: { amenity: 'marketplace', height: 0 }}),
|
|
iD.Entity({ type: 'node', tags: { amenity: 'school', height: 5, width: 3 }}),
|
|
iD.Entity({ type: 'node', tags: { amenity: 'healthcare' }}),
|
|
iD.Entity({ type: 'node', tags: { amenity: 'place_of_worship' }}),
|
|
];
|
|
var selectors = [
|
|
{
|
|
'geometry':'node',
|
|
'equals':{'amenity':'marketplace'},
|
|
'absence':'name',
|
|
'warning':'throwWarning: "[amenity=marketplace]: MapRules preset \'Market\': must be coupled with name";'
|
|
},
|
|
{
|
|
'geometry':'node',
|
|
'equals':{'man_made':'water_tap'},
|
|
'absence':'name',
|
|
'warning':'throwWarning: "[amenity=drinking_water][man_made=water_tap]: MapRules preset \'Water Tap\': must be coupled with name";'
|
|
},
|
|
{
|
|
'geometry':'node',
|
|
'equals':{'amenity':'marketplace'},
|
|
'presence':'height',
|
|
'lessThanEqual': { 'height': 0 },
|
|
'warning':'throwWarning: "[amenity=marketplace]: height must be greater than 0";'
|
|
},
|
|
{
|
|
'geometry': 'node',
|
|
'equals': {'amenity': 'school'},
|
|
'greaterThan': { 'height': 0 },
|
|
'greaterThanEqual': { 'width': 1 },
|
|
'lessThanEqual': { 'width': 10 },
|
|
'lessThan': { 'height': 10 },
|
|
'warning': 'this is the warning!'
|
|
},
|
|
{
|
|
'geometry': 'node',
|
|
'presence': 'amenity',
|
|
'positiveRegex': { amenity: ['^school$', '^healthcare$'] },
|
|
'error': 'amenity cannot be healthcare or school!'
|
|
}
|
|
];
|
|
var areaKeys = iD.Context().presets().areaKeys();
|
|
var rules = selectors.map(function(s) { return iD.utilMapCSSRule(s, areaKeys); });
|
|
it ('turns selector object in mapcssRule', function () {
|
|
var ruleKeys = [
|
|
'ruleChecks', 'type','buildChecks', 'selector', 'buildTagMap', 'matches',
|
|
'areaKeys', 'inferGeometry', 'geometryMatches','findWarnings'
|
|
];
|
|
rules.forEach(function(rule) {
|
|
expect(Object.keys(rule)).to.eql(ruleKeys);
|
|
});
|
|
});
|
|
describe('#type', function() {
|
|
it('is either error or warning', function() {
|
|
selectors.forEach(function(s) {
|
|
expect(['error', 'warning'].indexOf(iD.utilMapCSSRule(s, areaKeys).type)).to.be.greaterThan(-1);
|
|
});
|
|
});
|
|
});
|
|
describe('#geometryMatches', function() {
|
|
it('determines if entity and rule geometries match', function() {
|
|
var node = iD.Entity({ type: 'node'});
|
|
var way = iD.Entity({ type: 'way'});
|
|
var graph = iD.Graph([node, way]);
|
|
rules.forEach(function(rule) {
|
|
expect(rule.geometryMatches(node, graph)).to.be.true;
|
|
expect(rule.geometryMatches(way, graph)).to.be.false;
|
|
});
|
|
});
|
|
});
|
|
describe('#buildsChecks', function() {
|
|
it('builds array of MapCSS rule check functions to run entities against', function() {
|
|
rules.forEach(function(rule) {
|
|
expect(rule.buildChecks().every(function(fn) { return fn instanceof Function; })).to.be.true;
|
|
});
|
|
});
|
|
});
|
|
describe('#buildTagMap', function() {
|
|
it('builds tag map from selector config', function () {
|
|
var selector = {
|
|
'geometry':'node',
|
|
'equals':{'amenity':'marketplace'},
|
|
'positiveRegex': { 'marketplace:type': ['open', 'indoor', 'mall']},
|
|
'greaterThan': { 'width': 10, 'area': 300 },
|
|
'presence': 'opening_hours',
|
|
'absence':'name',
|
|
'warning':'throwWarning: "[amenity=marketplace]: MapRules preset \'Market\': must be coupled with name";'
|
|
};
|
|
var tagMap = {
|
|
'amenity':['marketplace'],
|
|
'marketplace:type':['open','indoor','mall'],
|
|
'width':[],
|
|
'opening_hours':[]
|
|
};
|
|
|
|
var rule = iD.utilMapCSSRule(selector, areaKeys);
|
|
expect(rule.buildTagMap()).to.be.eql(tagMap);
|
|
});
|
|
});
|
|
describe('#matches', function() {
|
|
it('determines if an entity matches the MapCSS rule checks', function() {
|
|
var node = iD.Entity({ type: 'node', tags: { power: 'tower' }});
|
|
rules.forEach(function(rule, i) {
|
|
expect(rule.matches(entities[i])).to.be.true;
|
|
expect(rule.matches(node)).to.be.false;
|
|
});
|
|
});
|
|
});
|
|
describe('#selector', function() {
|
|
it('returns selector used to construct rule', function() {
|
|
var rule = iD.utilMapCSSRule(selectors[1], areaKeys);
|
|
expect(rule.selector()).to.eql(selectors[1]);
|
|
});
|
|
});
|
|
describe('#areaKeys', function() {
|
|
it('returns areaKeys used to construct rule', function() {
|
|
var rule = iD.utilMapCSSRule(selectors[0], areaKeys);
|
|
expect(rule.areaKeys()).to.eql(areaKeys);
|
|
});
|
|
});
|
|
describe('#ruleChecks', function() {
|
|
describe('equals', function() {
|
|
it('is true when entity.tags intersects selector.equals', function() {
|
|
var pseudoSelector = { equals: {'amenity': 'school'} };
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var school = iD.Entity({ type: 'node', tags: { amenity: 'school' }});
|
|
expect(pseudoRule.ruleChecks.equals(school.tags)).to.be.true;
|
|
});
|
|
it('is false when entity.tags intersects selector.equals', function() {
|
|
var pseudoSelector = { equals: { 'man_made': 'water_tap'} };
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var school = iD.Entity({ type: 'node', tags: { amenity: 'school' } } );
|
|
expect(pseudoRule.ruleChecks.equals(school.tags)).to.be.false;
|
|
});
|
|
});
|
|
describe('notEquals', function() {
|
|
it('is true when entity.tags does not intersect selector.notEquals', function() {
|
|
var pseudoSelector = { notEquals: { 'man_made': 'water_tap'} };
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var school = iD.Entity({ type: 'node', tags: { amenity: 'school' } } );
|
|
expect(pseudoRule.ruleChecks.notEquals(school.tags)).to.be.true;
|
|
});
|
|
it('is false when entity.tags does not intersect selector.notEquals', function() {
|
|
var pseudoSelector = { notEquals: { 'amenity': 'school'} };
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var school = iD.Entity({ type: 'node', tags: { amenity: 'school' } } );
|
|
expect(pseudoRule.ruleChecks.notEquals(school.tags)).to.be.false;
|
|
});
|
|
});
|
|
describe('presence', function() {
|
|
it('is true when entity.tags\' key s include selector.presence', function() {
|
|
var pseudoSelector = { presence: 'name' };
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var kHouse = iD.Entity({ type: 'node', tags: { amenity: 'marketplace', name: 'Kensington Square' }});
|
|
expect(pseudoRule.ruleChecks.presence(kHouse.tags)).to.be.true;
|
|
});
|
|
it('is false when entity tags\' keys do not include selector.presence', function() {
|
|
var pseudoSelector = { presence: 'name' };
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var notKHouse = iD.Entity({ type: 'node', tags: { amenity: 'marketplace' }});
|
|
expect(pseudoRule.ruleChecks.presence(notKHouse.tags)).to.be.false;
|
|
});
|
|
});
|
|
describe('absence', function() {
|
|
it('is true when entity.tags\' keys do not include selector.absence', function() {
|
|
var pseudoSelector = { absence: 'name' };
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var notKHouse = iD.Entity({ type: 'node', tags: { amenity: 'marketplace' }});
|
|
expect(pseudoRule.ruleChecks.absence(notKHouse.tags)).to.be.true;
|
|
});
|
|
it('is false when entity.tags\' keys include selector.absence', function() {
|
|
var pseudoSelector = { absence: 'name' };
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var kHouse = iD.Entity({ type: 'node', tags: { amenity: 'marketplace', name: 'Kensington Square' }});
|
|
expect(pseudoRule.ruleChecks.presence(kHouse.tags)).to.be.false;
|
|
});
|
|
});
|
|
describe('greaterThan', function() {
|
|
it('is true when entity.tags\' equivalent value is greater than selector.greaterThan', function() {
|
|
var pseudoSelector = { greaterThan: { height: 10 }};
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var tallSchool = iD.Entity({ type: 'node', tags: { amenity: 'school', height: 9000 }});
|
|
expect(pseudoRule.ruleChecks.greaterThan(tallSchool.tags)).to.be.true;
|
|
});
|
|
it('is false when entity.tags\' equivalent value is less than or equal to selector.greaterThan', function() {
|
|
var pseudoSelector = { greaterThan: { height: 10 }};
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var smallSchool = iD.Entity({ type: 'node', tags: { amenity: 'school', height: 9 }});
|
|
expect(pseudoRule.ruleChecks.greaterThan(smallSchool.tags)).to.be.false;
|
|
});
|
|
});
|
|
describe('greaterThanEqual', function() {
|
|
it('is true when entity.tags\' equivalent value is greater than or equal to selector.greaterThanEqual', function() {
|
|
var pseudoSelector = { greaterThanEqual: { height: 10 } };
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var okHeightSchool = iD.Entity({ type: 'node', tags: { amenity: 'school', height: 10 }});
|
|
expect(pseudoRule.ruleChecks.greaterThanEqual(okHeightSchool.tags)).to.be.true;
|
|
});
|
|
it('is false when entity.tags\' equivalent value is less than to selector.greaterThanEqual', function() {
|
|
var pseudoSelector = { greaterThanEqual: { height: 10 }};
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var smallSchool = iD.Entity({ type: 'node', tags: { amenity: 'school', height: 9 }});
|
|
expect(pseudoRule.ruleChecks.greaterThanEqual(smallSchool.tags)).to.be.false;
|
|
});
|
|
});
|
|
describe('lessThan', function() {
|
|
it('is true when entity.tags\' equivalent value is less than to selector.lessThan', function() {
|
|
var pseudoSelector = { lessThan: { height: 10 } };
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var smallSchool = iD.Entity({ type: 'node', tags: { amenity: 'school', height: 3 }});
|
|
expect(pseudoRule.ruleChecks.lessThan(smallSchool.tags)).to.be.tru;
|
|
});
|
|
it('is false when entity.tags\' equivalent value is greater than or equal to selector.lessThan', function() {
|
|
var pseudoSelector = { lessThan: { height: 10 } };
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var notOkHeightSchool = iD.Entity({ type: 'node', tags: { amenity: 'school', height: 10 }});
|
|
expect(pseudoRule.ruleChecks.lessThan(notOkHeightSchool.tags)).to.be.false;
|
|
});
|
|
});
|
|
describe('lessThanEqual', function() {
|
|
it('is true when entity.tags\' equivalent value is less than or equal to to selector.lessThan', function() {
|
|
var pseudoSelector = { lessThanEqual: { height: 10 } };
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var okHeightSchool = iD.Entity({ type: 'node', tags: { 'amenity': 'school', 'height': 10 }});
|
|
expect(pseudoRule.ruleChecks.lessThanEqual(okHeightSchool.tags)).to.be.true;
|
|
});
|
|
it('is false when entity.tags\' equivalent value is greater than to selector.lessThan', function() {
|
|
var pseudoSelector = { lessThanEqual: { height: 10 } };
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var notOkHeightSchool = iD.Entity({ type: 'node', tags: { amenity: 'school', height: 11 }});
|
|
expect(pseudoRule.ruleChecks.lessThanEqual(notOkHeightSchool.tags)).to.be.false;
|
|
});
|
|
});
|
|
describe('positiveRegex', function() {
|
|
it('is true when entity.tags\' equivalent value matches regular expression built from selector.positiveRegex', function() {
|
|
var pseudoSelector = { positiveRegex: { amenity: ['^school$', '^healthcare$'] }};
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var okAmenities = [
|
|
iD.Entity({ type: 'node', tags: { amenity: 'school' }}),
|
|
iD.Entity({ type: 'node', tags: { amenity: 'healthcare' }})
|
|
];
|
|
okAmenities.forEach(function(amenity) {
|
|
expect(pseudoRule.ruleChecks.positiveRegex(amenity.tags)).to.be.true;
|
|
});
|
|
});
|
|
it('is false when entity.tags\' equivalent value does not match regular expression built from selector.positiveRegex', function() {
|
|
var pseudoSelector = { positiveRegex: { amenity: ['^school$', '^healthcare$'] }};
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var notOkAmenities = [
|
|
iD.Entity({ type: 'node', tags: { amenity: 'parking' }}),
|
|
iD.Entity({ type: 'node', tags: { amenity: 'place_of_worship' }})
|
|
];
|
|
notOkAmenities.forEach(function(amenity) {
|
|
expect(pseudoRule.ruleChecks.positiveRegex(amenity.tags)).to.be.false;
|
|
});
|
|
});
|
|
});
|
|
describe('negativeRegex', function() {
|
|
it('is true when entity.tags\' equivalent value does not match regular exprsesion built from selector.negativeRegex', function() {
|
|
var pseudoSelector = { negativeRegex: { amenity: ['^school$', '^healthcare$'] }};
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var notOkAmenities = [
|
|
iD.Entity({ type: 'node', tags: { amenity: 'parking' }}),
|
|
iD.Entity({ type: 'node', tags: { amenity: 'place_of_worship' }})
|
|
];
|
|
notOkAmenities.forEach(function(amenity) {
|
|
expect(pseudoRule.ruleChecks.negativeRegex(amenity.tags)).to.be.true;
|
|
});
|
|
});
|
|
it('is false when entity.tags\' equivalent value matches regular expression built from selector.negativeRegex', function() {
|
|
var pseudoSelector = { negativeRegex: { amenity: ['^school$', '^healthcare$'] }};
|
|
var pseudoRule = iD.utilMapCSSRule(pseudoSelector, areaKeys);
|
|
var okAmenities = [
|
|
iD.Entity({ type: 'node', tags: { amenity: 'school' }}),
|
|
iD.Entity({ type: 'node', tags: { amenity: 'healthcare' }})
|
|
];
|
|
okAmenities.forEach(function(amenity) {
|
|
expect(pseudoRule.ruleChecks.negativeRegex(amenity.tags)).to.be.false;
|
|
});
|
|
});
|
|
});
|
|
});
|
|
describe('#inferGeometry', function() {
|
|
it ('infers selector geometry from its tags', function() {
|
|
var amenityDerivedArea = {
|
|
'geometry': 'closedway',
|
|
'presence': 'amenity',
|
|
'positiveRegex': { amenity: ['^school$', '^healthcare$'] },
|
|
'error': 'amenity cannot be healthcare or school!'
|
|
};
|
|
|
|
var areaDerivedArea = {
|
|
'geometry': 'closedway',
|
|
'equals': { area: 'yes' },
|
|
};
|
|
|
|
var badAreaDerivedLine = {
|
|
'geometry': 'closedway',
|
|
'equals': { 'area': 'no' }
|
|
};
|
|
|
|
var roundHouseRailwayDerivedArea = {
|
|
'geometry': 'closedway',
|
|
'equals': { 'railway': 'roundhouse' }
|
|
};
|
|
|
|
var justClosedWayDerivedLine = {
|
|
'geometry': 'closedway'
|
|
};
|
|
|
|
var rule, geom;
|
|
rule = iD.utilMapCSSRule(amenityDerivedArea, areaKeys);
|
|
geom = rule.inferGeometry();
|
|
expect(geom).to.be.eql('area');
|
|
|
|
rule = iD.utilMapCSSRule(areaDerivedArea, areaKeys);
|
|
geom = rule.inferGeometry();
|
|
expect(geom).to.be.eql('area');
|
|
|
|
rule = iD.utilMapCSSRule(badAreaDerivedLine, areaKeys);
|
|
geom = rule.inferGeometry();
|
|
expect(geom).to.be.eql('line');
|
|
|
|
rule = iD.utilMapCSSRule(roundHouseRailwayDerivedArea, areaKeys);
|
|
geom = rule.inferGeometry();
|
|
expect(geom).to.be.eql('area');
|
|
|
|
rule = iD.utilMapCSSRule(justClosedWayDerivedLine, areaKeys);
|
|
geom = rule.inferGeometry();
|
|
expect(geom).to.be.eql('line');
|
|
});
|
|
});
|
|
describe('#findWarnings', function() {
|
|
it('adds found warnings to warnings array', function() {
|
|
var graph = iD.Graph([entities]);
|
|
var warnings = [];
|
|
|
|
rules.forEach(function(rule) {
|
|
entities.forEach(function(entity) {
|
|
rule.findWarnings(entity, graph, warnings);
|
|
});
|
|
});
|
|
|
|
warnings.forEach(function(warning) {
|
|
expect(warning.message).to.not.be.null;
|
|
expect(['mapcss_warning', 'mapcss_error'].indexOf(warning.id)).to.be.greaterThan(-1);
|
|
expect(warning.entity).to.be.instanceOf(iD.Entity);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|