mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-19 23:14:47 +02:00
move validations to its own class
ref #remote-presets
This commit is contained in:
@@ -464,10 +464,9 @@ export function coreContext() {
|
||||
var validationsUrl = utilStringQs(window.location.hash).validations;
|
||||
d3_json(validationsUrl, function (err, mapcss) {
|
||||
if (err) return;
|
||||
services.maprules.init();
|
||||
var areaKeys = context.presets().areaKeys();
|
||||
services.maprules.init(context.presets().areaKeys());
|
||||
_each(mapcss, function(mapcssSelector) {
|
||||
return services.maprules.addRule(mapcssSelector, areaKeys);
|
||||
return services.maprules.addRule(mapcssSelector);
|
||||
});
|
||||
context.validationRules = true;
|
||||
});
|
||||
|
||||
@@ -3,9 +3,6 @@ import _intersection from 'lodash-es/intersection';
|
||||
import _reduce from 'lodash-es/reduce';
|
||||
import _every from 'lodash-es/every';
|
||||
|
||||
var ruleChecks,
|
||||
validationRules;
|
||||
|
||||
var buildRuleChecks = function() {
|
||||
return {
|
||||
equals: function (equals) {
|
||||
@@ -81,17 +78,35 @@ var buildRuleChecks = function() {
|
||||
};
|
||||
};
|
||||
|
||||
var buildLineKeys = function() {
|
||||
return {
|
||||
highway: {
|
||||
rest_area: true,
|
||||
services: true
|
||||
},
|
||||
railway: {
|
||||
roundhouse: true,
|
||||
station: true,
|
||||
traverser: true,
|
||||
turntable: true,
|
||||
wash: true
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default {
|
||||
init: function() {
|
||||
ruleChecks = buildRuleChecks();
|
||||
validationRules = [];
|
||||
init: function(areaKeys) {
|
||||
this._ruleChecks = buildRuleChecks();
|
||||
this._validationRules = [];
|
||||
this._areaKeys = areaKeys;
|
||||
this._lineKeys = buildLineKeys();
|
||||
},
|
||||
// list of rules only relevant to tag checks...
|
||||
filterRuleChecks: function(selector) {
|
||||
var _ruleChecks = this._ruleChecks;
|
||||
return _reduce(Object.keys(selector), function(rules, key) {
|
||||
if (['geometry', 'error', 'warning'].indexOf(key) === -1) {
|
||||
rules.push(ruleChecks[key](selector[key]));
|
||||
rules.push(_ruleChecks[key](selector[key]));
|
||||
}
|
||||
return rules;
|
||||
}, []);
|
||||
@@ -123,8 +138,14 @@ export default {
|
||||
|
||||
} else if (/(greater|less)Than(Equal)?|presence/g.test(key)) {
|
||||
var tagKey = /presence/.test(key) ? selector[key] : Object.keys(selector[key])[0];
|
||||
expectedTags[tagKey] = [];
|
||||
|
||||
values = [selector[key][tagKey]];
|
||||
|
||||
if (expectedTags.hasOwnProperty(tagKey)) {
|
||||
values = values.concat(expectedTags[tagKey]);
|
||||
}
|
||||
|
||||
expectedTags[tagKey] = values;
|
||||
}
|
||||
|
||||
return expectedTags;
|
||||
@@ -133,25 +154,15 @@ export default {
|
||||
return tagMap;
|
||||
},
|
||||
// inspired by osmWay#isArea()
|
||||
inferGeometry: function(tagMap, areaKeys) {
|
||||
var lineKeys = {
|
||||
highway: {
|
||||
rest_area: true,
|
||||
services: true
|
||||
},
|
||||
railway: {
|
||||
roundhouse: true,
|
||||
station: true,
|
||||
traverser: true,
|
||||
turntable: true,
|
||||
wash: true
|
||||
}
|
||||
};
|
||||
inferGeometry: function(tagMap) {
|
||||
var _lineKeys = this._lineKeys;
|
||||
var _areaKeys = this._areaKeys;
|
||||
|
||||
var isAreaKeyBlackList = function(key) {
|
||||
return _intersection(tagMap[key], Object.keys(areaKeys[key])).length > 0;
|
||||
return _intersection(tagMap[key], Object.keys(_areaKeys[key])).length > 0;
|
||||
};
|
||||
var isLineKeysWhiteList = function(key) {
|
||||
return _intersection(tagMap[key], Object.keys(lineKeys[key])).length > 0;
|
||||
return _intersection(tagMap[key], Object.keys(_lineKeys[key])).length > 0;
|
||||
};
|
||||
|
||||
if (tagMap.hasOwnProperty('area')) {
|
||||
@@ -164,10 +175,10 @@ export default {
|
||||
}
|
||||
|
||||
for (var key in tagMap) {
|
||||
if (key in areaKeys && !isAreaKeyBlackList(key)) {
|
||||
if (key in _areaKeys && !isAreaKeyBlackList(key)) {
|
||||
return 'area';
|
||||
}
|
||||
if (key in lineKeys && isLineKeysWhiteList(key)) {
|
||||
if (key in _lineKeys && isLineKeysWhiteList(key)) {
|
||||
return 'area';
|
||||
}
|
||||
}
|
||||
@@ -175,7 +186,8 @@ export default {
|
||||
return 'line';
|
||||
},
|
||||
// adds from mapcss-parse selector check...
|
||||
addRule: function(selector, areaKeys) {
|
||||
addRule: function(selector) {
|
||||
var _areaKeys = this._areaKeys;
|
||||
var rule = {
|
||||
// checks relevant to mapcss-selector
|
||||
checks: this.filterRuleChecks(selector),
|
||||
@@ -186,7 +198,7 @@ export default {
|
||||
});
|
||||
},
|
||||
// borrowed from Way#isArea()
|
||||
inferredGeometry: this.inferGeometry(this.buildTagMap(selector), areaKeys),
|
||||
inferredGeometry: this.inferGeometry(this.buildTagMap(selector), this._areaKeys),
|
||||
geometryMatches: function(entity, graph) {
|
||||
if (entity.type === 'node' || entity.type === 'relation') {
|
||||
return selector.geometry === entity.type;
|
||||
@@ -206,8 +218,11 @@ export default {
|
||||
}
|
||||
}
|
||||
};
|
||||
validationRules.push(rule);
|
||||
this._validationRules.push(rule);
|
||||
},
|
||||
clearRules: function() { this._validationRules = []; },
|
||||
// returns validationRules...
|
||||
validationRules: function() { return validationRules; }
|
||||
validationRules: function() { return this._validationRules; },
|
||||
// returns ruleChecks
|
||||
ruleChecks: function() { return this._ruleChecks; }
|
||||
};
|
||||
|
||||
+3
-1
@@ -112,7 +112,9 @@
|
||||
<script src='spec/services/openstreetcam.js'></script>
|
||||
<script src='spec/services/osm.js'></script>
|
||||
<script src='spec/services/streetside.js'></script>
|
||||
<script src='spec/services/taginfo.js'></script>
|
||||
<script src='spec/services/taginfo.js'></script> -->
|
||||
|
||||
<script src='spec/services/maprules.js'></script>
|
||||
|
||||
<script src='spec/svg/areas.js'></script>
|
||||
<script src='spec/svg/data.js'></script>
|
||||
|
||||
@@ -0,0 +1,574 @@
|
||||
describe('maprules', function() {
|
||||
var _ruleChecks, validationRules;
|
||||
before(function() {
|
||||
var areaKeys = iD.Context().presets().areaKeys();
|
||||
iD.serviceMapRules.init(areaKeys);
|
||||
_ruleChecks = iD.serviceMapRules.ruleChecks();
|
||||
});
|
||||
|
||||
describe('#filterRuleChecks', function() {
|
||||
it('returns shortlist of mapcss checks relevant to provided selector', function() {
|
||||
var selector = {
|
||||
geometry: 'closedway',
|
||||
equals: {amenity: 'marketplace'},
|
||||
absence: 'name',
|
||||
error: '\'Marketplace\' preset must be coupled with name'
|
||||
};
|
||||
var filteredChecks = iD.serviceMapRules.filterRuleChecks(selector);
|
||||
var equalsCheck = filteredChecks[0];
|
||||
var absenceCheck = filteredChecks[1];
|
||||
var entityTags = {amenity: 'marketplace'};
|
||||
|
||||
expect(filteredChecks.length).eql(2);
|
||||
expect(equalsCheck(entityTags)).to.be.true;
|
||||
expect(absenceCheck(entityTags)).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe('#buildTagMap', function() {
|
||||
it('builds a map of tag keys/values found in mapcss selector', function() {
|
||||
[
|
||||
{
|
||||
t: {
|
||||
equals: {
|
||||
man_made: 'tower',
|
||||
'tower:type': 'communication'
|
||||
}
|
||||
},
|
||||
r: {
|
||||
man_made: ['tower'],
|
||||
'tower:type': ['communication']
|
||||
}
|
||||
},
|
||||
{
|
||||
t: {
|
||||
equals: {
|
||||
building: 'yes',
|
||||
amenity: 'school'
|
||||
},
|
||||
positiveRegex: {
|
||||
opening_hours: [
|
||||
'24/7',
|
||||
'sunrise_sundown'
|
||||
]
|
||||
},
|
||||
negativeRegex: {
|
||||
source: [
|
||||
'missing_maps',
|
||||
'american_red_cross'
|
||||
]
|
||||
},
|
||||
greaterThanEqual: { floors: 2 },
|
||||
lessThanEqual: { floors: 4 }
|
||||
|
||||
},
|
||||
r: {
|
||||
building: ['yes'],
|
||||
amenity: ['school'],
|
||||
opening_hours: ['24/7', 'sunrise_sundown'],
|
||||
source: ['missing_maps', 'american_red_cross'],
|
||||
floors: [4, 2]
|
||||
}
|
||||
},
|
||||
{
|
||||
t: {
|
||||
equals: { highway: 'yes' },
|
||||
greaterThan: { lanes: 1 },
|
||||
lessThan: { lanes: 4 }
|
||||
},
|
||||
r: {
|
||||
highway: ['yes'],
|
||||
lanes: [4, 1]
|
||||
}
|
||||
}
|
||||
].forEach(function(test) {
|
||||
expect(iD.serviceMapRules.buildTagMap(test.t)).to.eql(test.r);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#inferGeometry', function() {
|
||||
it('infers geometry using selector keys', 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 tagMap, geom;
|
||||
tagMap = iD.serviceMapRules.buildTagMap(amenityDerivedArea);
|
||||
geom = iD.serviceMapRules.inferGeometry(tagMap);
|
||||
expect(geom).to.be.eql('area');
|
||||
|
||||
tagMap = iD.serviceMapRules.buildTagMap(areaDerivedArea);
|
||||
geom = iD.serviceMapRules.inferGeometry(tagMap);
|
||||
expect(geom).to.be.eql('area');
|
||||
|
||||
tagMap = iD.serviceMapRules.buildTagMap(badAreaDerivedLine);
|
||||
geom = iD.serviceMapRules.inferGeometry(tagMap);
|
||||
expect(geom).to.be.eql('line');
|
||||
|
||||
tagMap = iD.serviceMapRules.buildTagMap(roundHouseRailwayDerivedArea);
|
||||
geom = iD.serviceMapRules.inferGeometry(tagMap);
|
||||
expect(geom).to.be.eql('area');
|
||||
|
||||
tagMap = iD.serviceMapRules.buildTagMap(justClosedWayDerivedLine);
|
||||
geom = iD.serviceMapRules.inferGeometry(tagMap);
|
||||
expect(geom).to.be.eql('line');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#addRule', function() {
|
||||
it ('builds a rule from provided selector and adds it to _validationRules', function () {
|
||||
var selector = {
|
||||
geometry:'node',
|
||||
equals: {amenity:'marketplace'},
|
||||
absence:'name',
|
||||
warning:'\'Marketplace\' preset must be coupled with name'
|
||||
};
|
||||
expect(iD.serviceMapRules.validationRules()).to.be.empty;
|
||||
iD.serviceMapRules.addRule(selector);
|
||||
expect(iD.serviceMapRules.validationRules().length).to.eql(1);
|
||||
});
|
||||
});
|
||||
describe('#clearRules', function() {
|
||||
it ('clears _validationRules array', function() {
|
||||
expect(iD.serviceMapRules.validationRules().length).to.eql(1);
|
||||
iD.serviceMapRules.clearRules();
|
||||
expect(iD.serviceMapRules.validationRules()).to.be.empty;
|
||||
});
|
||||
});
|
||||
|
||||
describe('#validationRules', function() {
|
||||
it('returns _validationRules array', function() {
|
||||
var selector = {
|
||||
geometry: 'closedway',
|
||||
equals: {amenity: 'marketplace'},
|
||||
absence: 'name',
|
||||
error: '\'Marketplace\' preset must be coupled with name'
|
||||
};
|
||||
iD.serviceMapRules.addRule(selector);
|
||||
var rules = iD.serviceMapRules.validationRules();
|
||||
expect(rules).instanceof(Array);
|
||||
expect(rules.length).to.eql(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_ruleChecks', function () {
|
||||
describe('#equals', function() {
|
||||
it('is true when two tag maps intersect', function() {
|
||||
var a = { amenity: 'school'};
|
||||
var b = { amenity: 'school' };
|
||||
expect(_ruleChecks.equals(a)(b)).to.be.true;
|
||||
});
|
||||
it('is false when two tag maps intersect', function() {
|
||||
var a = { man_made: 'water_tap'};
|
||||
var b = { amenity: 'school'};
|
||||
expect(_ruleChecks.equals(a)(b)).to.be.false;
|
||||
});
|
||||
});
|
||||
describe('#notEquals', function() {
|
||||
it('is true when two tag maps do not intersect', function() {
|
||||
var a = { man_made: 'water_tap'};
|
||||
var b = { amenity: 'school' };
|
||||
expect(_ruleChecks.notEquals(a)(b)).to.be.true;
|
||||
});
|
||||
it('is not true when two tag maps intersect', function() {
|
||||
var a = { amenity: 'school' };
|
||||
var b = { amenity: 'school', opening_hours: '9-5' };
|
||||
expect(_ruleChecks.notEquals(a)(b)).to.be.false;
|
||||
});
|
||||
});
|
||||
describe('absence', function() {
|
||||
it('is true when tag map keys does not include key in question', function() {
|
||||
var key = 'amenity';
|
||||
var map = { building: 'yes' };
|
||||
expect(_ruleChecks.absence(key)(map)).to.be.true;
|
||||
});
|
||||
it('is false when tag map keys does include key in question', function() {
|
||||
var key = 'amenity';
|
||||
var map = { amenity: 'school' };
|
||||
expect(_ruleChecks.absence(key)(map)).to.be.false;
|
||||
});
|
||||
});
|
||||
describe('presence', function() {
|
||||
it('is true when tag map keys includes key in question', function() {
|
||||
var key = 'amenity';
|
||||
var map = { amenity: 'school'};
|
||||
expect(_ruleChecks.presence(key)(map)).to.be.true;
|
||||
});
|
||||
it('is false when tag map keys do not include key in question', function() {
|
||||
var key = 'amenity';
|
||||
var map = { building: 'yes'};
|
||||
expect(_ruleChecks.presence(key)(map)).to.be.false;
|
||||
});
|
||||
});
|
||||
describe('greaterThan', function() {
|
||||
it ('is true when a tag value is greater than the selector value', function() {
|
||||
var selectorTags = { lanes: 5 };
|
||||
var tags = { lanes : 6 };
|
||||
expect(_ruleChecks.greaterThan(selectorTags)(tags)).to.be.true;
|
||||
});
|
||||
it ('is false when a tag value is less than or equal to the selector value', function() {
|
||||
var selectorTags = { lanes: 5 };
|
||||
[4, 5].forEach(function(val) {
|
||||
expect(_ruleChecks.greaterThan(selectorTags)({ lanes: val })).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('greaterThanEqual', function() {
|
||||
it ('is true when a tag value is greater than or equal to the selector value', function() {
|
||||
var selectorTags = { lanes: 5 };
|
||||
[5, 6].forEach(function(val) {
|
||||
expect(_ruleChecks.greaterThanEqual(selectorTags)({ lanes: val })).to.be.true;
|
||||
});
|
||||
});
|
||||
it ('is false when a tag value is less than the selector value', function () {
|
||||
var selectorTags = { lanes: 5 };
|
||||
var tags = { lanes: 4 };
|
||||
expect(_ruleChecks.greaterThanEqual(selectorTags)(tags)).to.be.false;
|
||||
});
|
||||
});
|
||||
describe('lessThan', function() {
|
||||
it ('is true when a tag value is less than the selector value', function() {
|
||||
var selectorTags = { lanes: 5 };
|
||||
var tags = { lanes: 4 };
|
||||
expect(_ruleChecks.lessThan(selectorTags)(tags)).to.be.true;
|
||||
});
|
||||
it ('is false when a tag value is greater than or equal to the selector value', function() {
|
||||
var selectorTags = { lanes: 5 };
|
||||
[6, 7].forEach(function(val) {
|
||||
expect(_ruleChecks.lessThan(selectorTags)({ lanes: val })).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('lessThanEqual', function() {
|
||||
it ('is true when a tag value is less than or equal to the selector value', function() {
|
||||
var selectorTags = { lanes: 5 };
|
||||
[4, 5].forEach(function(val) {
|
||||
expect(_ruleChecks.lessThanEqual(selectorTags)({ lanes: val })).to.be.true;
|
||||
});
|
||||
});
|
||||
it ('is false when a tag value is greater than the selector value', function() {
|
||||
var selectorTags = { lanes: 5 };
|
||||
var tags = { lanes: 6 };
|
||||
expect(_ruleChecks.lessThanEqual(selectorTags)(tags)).to.be.false;
|
||||
});
|
||||
});
|
||||
describe('positiveRegex', function() {
|
||||
var positiveRegex = { amenity: ['^hospital$','^clinic$']};
|
||||
it ('is true when tag value matches positiveRegex', function() {
|
||||
var tags = { amenity: 'hospital' };
|
||||
expect(_ruleChecks.positiveRegex(positiveRegex)(tags)).to.be.true;
|
||||
});
|
||||
it ('is false when tag value does not match negative regex', function() {
|
||||
var tags = { amenity: 'school' };
|
||||
expect(_ruleChecks.positiveRegex(positiveRegex)(tags)).to.be.false;
|
||||
});
|
||||
});
|
||||
describe('negativeRegex', function() {
|
||||
var negativeRegex = { bicycle: [ 'use_path', 'designated' ] };
|
||||
it ('is true when tag value does not match negativeRegex', function() {
|
||||
var tags = { bicycle: 'yes' };
|
||||
expect(_ruleChecks.negativeRegex(negativeRegex)(tags)).to.be.true;
|
||||
});
|
||||
it ('is false when tag value matches negativeRegex', function() {
|
||||
var tags = { bicycle: 'designated' };
|
||||
expect(_ruleChecks.negativeRegex(negativeRegex)(tags)).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('rule', function() {
|
||||
var selectors, entities;
|
||||
before(function() {
|
||||
selectors = [
|
||||
{
|
||||
geometry:'node',
|
||||
equals: {amenity:'marketplace'},
|
||||
absence:'name',
|
||||
error:'\'Marketplace\' preset must be coupled with name'
|
||||
},
|
||||
{
|
||||
geometry: 'closedway',
|
||||
notEquals: { building: 'yes', amenity: 'clinic' },
|
||||
error: '\'Clinic\' preset must be coupled with building=yes'
|
||||
},
|
||||
{
|
||||
geometry:'node',
|
||||
equals: {man_made: 'tower', 'tower:type': 'communication'},
|
||||
presence: 'height',
|
||||
error:'\'Communication Tower\' preset must not be coupled with height'
|
||||
},
|
||||
{
|
||||
geometry: 'node',
|
||||
equals: { man_made: 'tower' },
|
||||
lessThanEqual: { height: 6 },
|
||||
error: '\'Tower\' preset height must be greater than 6'
|
||||
},
|
||||
{
|
||||
geometry: 'node',
|
||||
equals: { man_made: 'tower' },
|
||||
greaterThanEqual: { height: 9 },
|
||||
error: '\'Tower\' preset height must be less than 9'
|
||||
},
|
||||
{
|
||||
geometry: 'node',
|
||||
equals: { man_made: 'tower' },
|
||||
lessThan: { height: 6 },
|
||||
error: '\'Tower\' preset height must be greater than or equal to 6'
|
||||
},
|
||||
{
|
||||
geometry: 'node',
|
||||
equals: { man_made: 'tower' },
|
||||
greaterThan: { height: 9 },
|
||||
error: '\'Tower\' preset height must be greater less than or equal to 9'
|
||||
},
|
||||
{
|
||||
geometry: 'closedway',
|
||||
equals: { amenity: 'clinic' },
|
||||
negativeRegex: { emergency: ['yes', 'no'] },
|
||||
error: '\'Clinic\' preset\'s emergency tag must be equal to \'yes\' or \'no\''
|
||||
},
|
||||
{
|
||||
geometry: 'way',
|
||||
equals: { highway: 'residential' },
|
||||
positiveRegex: { structure: ['bridge', 'tunnel'] },
|
||||
error: '\'suburban road\' structure tag cannot be \'bridge\' or \'tunnel\''
|
||||
}
|
||||
];
|
||||
entities = [
|
||||
iD.Entity({ type: 'node', tags: { amenity: 'marketplace' }}),
|
||||
iD.Way({ tags: { building: 'house', amenity: 'clinic' }, nodes: [ 'a', 'b', 'c', 'a' ]}),
|
||||
iD.Entity({ type: 'node', tags: { man_made: 'tower', 'tower:type': 'communication', height: 5 }}),
|
||||
iD.Entity({ type: 'node', tags: { man_made: 'tower', height: 6 }}),
|
||||
iD.Entity({ type: 'node', tags: { man_made: 'tower', height: 9 }}),
|
||||
iD.Entity({ type: 'node', tags: { man_made: 'tower', height: 5 }}),
|
||||
iD.Entity({ type: 'node', tags: { man_made: 'tower', height: 10 }}),
|
||||
iD.Way({ tags: { amenity: 'clinic', emergency: 'definitely' }, nodes: [ 'd', 'e', 'f', 'd' ]}),
|
||||
iD.Way({ tags: { highway: 'residential', structure: 'bridge' }}),
|
||||
];
|
||||
|
||||
iD.serviceMapRules.clearRules();
|
||||
selectors.forEach(function(selector) { iD.serviceMapRules.addRule(selector); });
|
||||
validationRules = iD.serviceMapRules.validationRules();
|
||||
});
|
||||
describe('#matches', function() {
|
||||
var selectors, entities;
|
||||
before(function() {
|
||||
selectors = [
|
||||
{
|
||||
geometry:'node',
|
||||
equals: {amenity:'marketplace'},
|
||||
absence:'name',
|
||||
error:'\'Marketplace\' preset must be coupled with name'
|
||||
},
|
||||
{
|
||||
geometry: 'closedway',
|
||||
notEquals: { building: 'yes', amenity: 'clinic' },
|
||||
error: '\'Clinic\' preset must be coupled with building=yes'
|
||||
},
|
||||
{
|
||||
geometry:'node',
|
||||
equals: {man_made: 'tower', 'tower:type': 'communication'},
|
||||
presence: 'height',
|
||||
error:'\'Communication Tower\' preset must not be coupled with height'
|
||||
},
|
||||
{
|
||||
geometry: 'node',
|
||||
equals: { man_made: 'tower' },
|
||||
lessThanEqual: { height: 6 },
|
||||
error: '\'Tower\' preset height must be greater than 6'
|
||||
},
|
||||
{
|
||||
geometry: 'node',
|
||||
equals: { man_made: 'tower' },
|
||||
greaterThanEqual: { height: 9 },
|
||||
error: '\'Tower\' preset height must be less than 9'
|
||||
},
|
||||
{
|
||||
geometry: 'node',
|
||||
equals: { man_made: 'tower' },
|
||||
lessThan: { height: 6 },
|
||||
error: '\'Tower\' preset height must be greater than or equal to 6'
|
||||
},
|
||||
{
|
||||
geometry: 'node',
|
||||
equals: { man_made: 'tower' },
|
||||
greaterThan: { height: 9 },
|
||||
error: '\'Tower\' preset height must be greater less than or equal to 9'
|
||||
},
|
||||
{
|
||||
geometry: 'closedway',
|
||||
equals: { amenity: 'clinic' },
|
||||
negativeRegex: { emergency: ['yes', 'no'] },
|
||||
error: '\'Clinic\' preset\'s emergency tag must be equal to \'yes\' or \'no\''
|
||||
},
|
||||
{
|
||||
geometry: 'way',
|
||||
equals: { highway: 'residential' },
|
||||
positiveRegex: { structure: ['bridge', 'tunnel'] },
|
||||
error: '\'suburban road\' structure tag cannot be \'bridge\' or \'tunnel\''
|
||||
}
|
||||
];
|
||||
entities = [
|
||||
iD.Entity({ type: 'node', tags: { amenity: 'marketplace' }}),
|
||||
iD.Way({ tags: { building: 'house', amenity: 'clinic' }, nodes: [ 'a', 'b', 'c', 'a' ]}),
|
||||
iD.Entity({ type: 'node', tags: { man_made: 'tower', 'tower:type': 'communication', height: 5 }}),
|
||||
iD.Entity({ type: 'node', tags: { man_made: 'tower', height: 6 }}),
|
||||
iD.Entity({ type: 'node', tags: { man_made: 'tower', height: 9 }}),
|
||||
iD.Entity({ type: 'node', tags: { man_made: 'tower', height: 5 }}),
|
||||
iD.Entity({ type: 'node', tags: { man_made: 'tower', height: 10 }}),
|
||||
iD.Way({ tags: { amenity: 'clinic', emergency: 'definitely' }, nodes: [ 'd', 'e', 'f', 'd' ]}),
|
||||
iD.Way({ tags: { highway: 'residential', structure: 'bridge' }}),
|
||||
];
|
||||
|
||||
iD.serviceMapRules.clearRules();
|
||||
selectors.forEach(function(selector) { iD.serviceMapRules.addRule(selector); });
|
||||
validationRules = iD.serviceMapRules.validationRules();
|
||||
});
|
||||
it('is true when each rule check is \'true\'', function() {
|
||||
validationRules.forEach(function(rule, i) {
|
||||
expect(rule.matches(entities[i])).to.be.true;
|
||||
});
|
||||
});
|
||||
it ('is true when at least one rule check is \'false\'', function() {
|
||||
var selector = {
|
||||
geometry: 'way',
|
||||
equals: { highway: 'residential' },
|
||||
positiveRegex: { structure: ['embarkment', 'bridge'] },
|
||||
error: '\'suburban road\' structure tag cannot be \'bridge\' or \'tunnel\''
|
||||
};
|
||||
var entity = iD.Way({ tags: { highway: 'residential', structure: 'tunnel' }});
|
||||
iD.serviceMapRules.clearRules();
|
||||
iD.serviceMapRules.addRule(selector);
|
||||
var rule = iD.serviceMapRules.validationRules()[0];
|
||||
|
||||
expect(rule.matches(entity)).to.be.false;
|
||||
});
|
||||
});
|
||||
describe('#findWarnings', function() {
|
||||
var selectors, entities, _graph;
|
||||
|
||||
before(function() {
|
||||
selectors = [
|
||||
{
|
||||
geometry:'node',
|
||||
equals: {amenity:'marketplace'},
|
||||
absence:'name',
|
||||
error:'\'Marketplace\' preset must be coupled with name'
|
||||
},
|
||||
{
|
||||
geometry: 'closedway',
|
||||
notEquals: { building: 'yes', amenity: 'clinic' },
|
||||
error: '\'Clinic\' preset must be coupled with building=yes'
|
||||
},
|
||||
{
|
||||
geometry:'node',
|
||||
equals: {man_made: 'tower', 'tower:type': 'communication'},
|
||||
presence: 'height',
|
||||
error:'\'Communication Tower\' preset must not be coupled with height'
|
||||
},
|
||||
{
|
||||
geometry: 'node',
|
||||
equals: { man_made: 'tower' },
|
||||
lessThanEqual: { height: 6 },
|
||||
error: '\'Tower\' preset height must be greater than 6'
|
||||
},
|
||||
{
|
||||
geometry: 'node',
|
||||
equals: { man_made: 'tower' },
|
||||
greaterThanEqual: { height: 9 },
|
||||
error: '\'Tower\' preset height must be less than 9'
|
||||
},
|
||||
{
|
||||
geometry: 'node',
|
||||
equals: { man_made: 'tower' },
|
||||
lessThan: { height: 6 },
|
||||
error: '\'Tower\' preset height must be greater than or equal to 6'
|
||||
},
|
||||
{
|
||||
geometry: 'node',
|
||||
equals: { man_made: 'tower' },
|
||||
greaterThan: { height: 9 },
|
||||
error: '\'Tower\' preset height must be greater less than or equal to 9'
|
||||
},
|
||||
{
|
||||
geometry: 'closedway',
|
||||
equals: { amenity: 'clinic' },
|
||||
negativeRegex: { emergency: ['yes', 'no'] },
|
||||
error: '\'Clinic\' preset\'s emergency tag must be equal to \'yes\' or \'no\''
|
||||
},
|
||||
{
|
||||
geometry: 'way',
|
||||
equals: { highway: 'residential' },
|
||||
positiveRegex: { structure: ['bridge', 'tunnel'] },
|
||||
error: '\'suburban road\' structure tag cannot be \'bridge\' or \'tunnel\''
|
||||
}
|
||||
];
|
||||
entities = [
|
||||
iD.Entity({ type: 'node', tags: { amenity: 'marketplace' }}),
|
||||
iD.Way({ tags: { building: 'house', amenity: 'clinic' }, nodes: [ 'a', 'b', 'c', 'a' ]}),
|
||||
iD.Entity({ type: 'node', tags: { man_made: 'tower', 'tower:type': 'communication', height: 5 }}),
|
||||
iD.Entity({ type: 'node', tags: { man_made: 'tower', height: 6 }}),
|
||||
iD.Entity({ type: 'node', tags: { man_made: 'tower', height: 9 }}),
|
||||
iD.Entity({ type: 'node', tags: { man_made: 'tower', height: 5 }}),
|
||||
iD.Entity({ type: 'node', tags: { man_made: 'tower', height: 10 }}),
|
||||
iD.Way({ tags: { amenity: 'clinic', emergency: 'definitely' }, nodes: [ 'd', 'e', 'f', 'd' ]}),
|
||||
iD.Way({ tags: { highway: 'residential', structure: 'bridge' }}),
|
||||
];
|
||||
|
||||
var wayNodes = [
|
||||
iD.osmNode({ id: 'a' }),
|
||||
iD.osmNode({ id: 'b' }),
|
||||
iD.osmNode({ id: 'c' }),
|
||||
iD.osmNode({ id: 'd' }),
|
||||
iD.osmNode({ id: 'e' }),
|
||||
iD.osmNode({ id: 'f' }),
|
||||
];
|
||||
_graph = iD.Graph(entities.concat(wayNodes));
|
||||
iD.serviceMapRules.clearRules();
|
||||
selectors.forEach(function(selector) { iD.serviceMapRules.addRule(selector); });
|
||||
validationRules = iD.serviceMapRules.validationRules();
|
||||
});
|
||||
it('finds warnings', function() {
|
||||
validationRules.forEach(function(rule, i) {
|
||||
var warnings = [];
|
||||
var entity = entities[i];
|
||||
var selector = selectors[i];
|
||||
|
||||
rule.findWarnings(entity, _graph, warnings);
|
||||
|
||||
var warning = warnings[0];
|
||||
var type = Object.keys(selector).indexOf('error') ? 'error' : 'warning';
|
||||
|
||||
expect(warnings.length).to.eql(1);
|
||||
expect(warning.entity).to.eql(entity);
|
||||
expect(warning.message).to.eql(selector[type]);
|
||||
expect('mapcss_' + type).to.eql(warning.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,356 +0,0 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user