forked from MapComplete/MapComplete
Add tests for tags, add check for duplicate names as layer ids, fix #393
This commit is contained in:
parent
fa9313a3b7
commit
33e2dca7e4
7 changed files with 95 additions and 60 deletions
|
@ -56,7 +56,6 @@ export class InitUiElements {
|
||||||
|
|
||||||
console.log("Using layout: ", layoutToUse.id, "LayoutFromBase64 is ", layoutFromBase64);
|
console.log("Using layout: ", layoutToUse.id, "LayoutFromBase64 is ", layoutFromBase64);
|
||||||
|
|
||||||
|
|
||||||
State.state = new State(layoutToUse);
|
State.state = new State(layoutToUse);
|
||||||
|
|
||||||
// This 'leaks' the global state via the window object, useful for debugging
|
// This 'leaks' the global state via the window object, useful for debugging
|
||||||
|
@ -212,7 +211,7 @@ export class InitUiElements {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static LoadLayoutFromHash(userLayoutParam: UIEventSource<string>): [LayoutConfig, string]{
|
static LoadLayoutFromHash(userLayoutParam: UIEventSource<string>): [LayoutConfig, string] {
|
||||||
try {
|
try {
|
||||||
let hash = location.hash.substr(1);
|
let hash = location.hash.substr(1);
|
||||||
const layoutFromBase64 = userLayoutParam.data;
|
const layoutFromBase64 = userLayoutParam.data;
|
||||||
|
@ -284,7 +283,7 @@ export class InitUiElements {
|
||||||
})
|
})
|
||||||
|
|
||||||
State.state.selectedElement.addCallbackAndRunD(_ => {
|
State.state.selectedElement.addCallbackAndRunD(_ => {
|
||||||
isOpened.setData(false);
|
isOpened.setData(false);
|
||||||
})
|
})
|
||||||
isOpened.setData(Hash.hash.data === undefined || Hash.hash.data === "" || Hash.hash.data == "welcome")
|
isOpened.setData(Hash.hash.data === undefined || Hash.hash.data === "" || Hash.hash.data == "welcome")
|
||||||
}
|
}
|
||||||
|
@ -333,8 +332,8 @@ export class InitUiElements {
|
||||||
});
|
});
|
||||||
|
|
||||||
State.state.selectedElement.addCallbackAndRunD(_ => {
|
State.state.selectedElement.addCallbackAndRunD(_ => {
|
||||||
layerControlButton.isEnabled.setData(false);
|
layerControlButton.isEnabled.setData(false);
|
||||||
copyrightButton.isEnabled.setData(false);
|
copyrightButton.isEnabled.setData(false);
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -345,7 +344,7 @@ export class InitUiElements {
|
||||||
|
|
||||||
State.state.backgroundLayer = State.state.backgroundLayerId
|
State.state.backgroundLayer = State.state.backgroundLayerId
|
||||||
.map((selectedId: string) => {
|
.map((selectedId: string) => {
|
||||||
if(selectedId === undefined){
|
if (selectedId === undefined) {
|
||||||
return AvailableBaseLayers.osmCarto
|
return AvailableBaseLayers.osmCarto
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,7 @@ export class Or extends TagsFilter {
|
||||||
const choices = [];
|
const choices = [];
|
||||||
for (const tagsFilter of this.or) {
|
for (const tagsFilter of this.or) {
|
||||||
const subChoices = tagsFilter.asOverpass();
|
const subChoices = tagsFilter.asOverpass();
|
||||||
for (const subChoice of subChoices) {
|
choices.push(...subChoices)
|
||||||
choices.push(subChoice)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return choices;
|
return choices;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,9 @@ export class RegexTag extends TagsFilter {
|
||||||
|
|
||||||
asOverpass(): string[] {
|
asOverpass(): string[] {
|
||||||
if (typeof this.key === "string") {
|
if (typeof this.key === "string") {
|
||||||
return [`['${this.key}'${this.invert ? "!" : ""}~'${RegexTag.source(this.value)}']`];
|
return [`["${this.key}"${this.invert ? "!" : ""}~"${RegexTag.source(this.value)}"]`];
|
||||||
}
|
}
|
||||||
return [`[~'${this.key.source}'${this.invert ? "!" : ""}~'${RegexTag.source(this.value)}']`];
|
return [`[~"${this.key.source}"${this.invert ? "!" : ""}~"${RegexTag.source(this.value)}"]`];
|
||||||
}
|
}
|
||||||
|
|
||||||
isUsableAsAnswer(): boolean {
|
isUsableAsAnswer(): boolean {
|
||||||
|
|
|
@ -10,7 +10,12 @@
|
||||||
{
|
{
|
||||||
"or": [
|
"or": [
|
||||||
"leisure=nature_reserve",
|
"leisure=nature_reserve",
|
||||||
"boundary=protected_area"
|
{
|
||||||
|
"and": [
|
||||||
|
"protect_class!=98",
|
||||||
|
"boundary=protected_area"
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
"socialImage": "./assets/themes/buurtnatuur/social_image.jpg",
|
"socialImage": "./assets/themes/buurtnatuur/social_image.jpg",
|
||||||
"layers": [
|
"layers": [
|
||||||
{
|
{
|
||||||
"id": "nature_reserve",
|
"id": "nature_reserve_buurtnatuur",
|
||||||
"name": {
|
"name": {
|
||||||
"nl": "Natuurgebied"
|
"nl": "Natuurgebied"
|
||||||
},
|
},
|
||||||
|
@ -141,7 +141,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"calculatedTags": [
|
"calculatedTags": [
|
||||||
"_overlapWithUpperLayers=Math.max(...feat.overlapWith('nature_reserve').map(o => o.overlap))/feat.area",
|
"_overlapWithUpperLayers=Math.max(...feat.overlapWith('nature_reserve_buurtnatuur').map(o => o.overlap))/feat.area",
|
||||||
"_tooMuchOverlap=Number(feat.properties._overlapWithUpperLayers) > 0.1 ? 'yes' :'no'"
|
"_tooMuchOverlap=Number(feat.properties._overlapWithUpperLayers) > 0.1 ? 'yes' :'no'"
|
||||||
],
|
],
|
||||||
"isShown": {
|
"isShown": {
|
||||||
|
@ -240,7 +240,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"calculatedTags": [
|
"calculatedTags": [
|
||||||
"_overlapWithUpperLayers=Math.max(...feat.overlapWith('parks','nature_reserve').map(o => o.overlap))/feat.area",
|
"_overlapWithUpperLayers=Math.max(...feat.overlapWith('parks','nature_reserve_buurtnatuur').map(o => o.overlap))/feat.area",
|
||||||
"_tooMuchOverlap=Number(feat.properties._overlapWithUpperLayers) > 0.1 ? 'yes' : 'no'"
|
"_tooMuchOverlap=Number(feat.properties._overlapWithUpperLayers) > 0.1 ? 'yes' : 'no'"
|
||||||
],
|
],
|
||||||
"isShown": {
|
"isShown": {
|
||||||
|
|
|
@ -140,6 +140,7 @@ class LayerOverviewUtils {
|
||||||
const layerFiles = lt.layers;
|
const layerFiles = lt.layers;
|
||||||
const themeFiles = lt.themes;
|
const themeFiles = lt.themes;
|
||||||
|
|
||||||
|
|
||||||
console.log(" ---------- VALIDATING ---------")
|
console.log(" ---------- VALIDATING ---------")
|
||||||
const licensePaths = []
|
const licensePaths = []
|
||||||
for (const i in licenses) {
|
for (const i in licenses) {
|
||||||
|
@ -151,6 +152,9 @@ class LayerOverviewUtils {
|
||||||
const knownLayerIds = new Map<string, LayerConfig>();
|
const knownLayerIds = new Map<string, LayerConfig>();
|
||||||
for (const layerFile of layerFiles) {
|
for (const layerFile of layerFiles) {
|
||||||
|
|
||||||
|
if (knownLayerIds.has(layerFile.parsed.id)) {
|
||||||
|
throw "Duplicate identifier: " + layerFile.parsed.id + " in file " + layerFile.path
|
||||||
|
}
|
||||||
layerErrorCount.push(...this.validateLayer(layerFile.parsed, layerFile.path, knownPaths))
|
layerErrorCount.push(...this.validateLayer(layerFile.parsed, layerFile.path, knownPaths))
|
||||||
knownLayerIds.set(layerFile.parsed.id, new LayerConfig(layerFile.parsed, AllKnownLayers.sharedUnits))
|
knownLayerIds.set(layerFile.parsed.id, new LayerConfig(layerFile.parsed, AllKnownLayers.sharedUnits))
|
||||||
}
|
}
|
||||||
|
@ -170,21 +174,21 @@ class LayerOverviewUtils {
|
||||||
missingTranslations.push(...this.validateTranslationCompletenessOfObject(layerConfig, themeFile.language, "Layer " + layer))
|
missingTranslations.push(...this.validateTranslationCompletenessOfObject(layerConfig, themeFile.language, "Layer " + layer))
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else if (layer.builtin !== undefined) {
|
||||||
let names = layer.builtin;
|
let names = layer.builtin;
|
||||||
if (names !== undefined) {
|
if (typeof names === "string") {
|
||||||
if (typeof names === "string") {
|
names = [names]
|
||||||
names = [names]
|
}
|
||||||
|
names.forEach(name => {
|
||||||
|
if (!knownLayerIds.has(name)) {
|
||||||
|
themeErrorCount.push("Unknown layer id: " + name + "(which uses inheritance)")
|
||||||
}
|
}
|
||||||
names.forEach(name => {
|
return
|
||||||
if (!knownLayerIds.has(name)) {
|
})
|
||||||
themeErrorCount.push("Unknown layer id: " + name + "(which uses inheritance)")
|
} else {
|
||||||
}
|
layerErrorCount.push(...this.validateLayer(layer, undefined, knownPaths, themeFile.id))
|
||||||
return
|
if (knownLayerIds.has(layer.id)) {
|
||||||
})
|
throw `The theme ${themeFile.id} defines a layer with id ${layer.id}, which is the same as an already existing layer`
|
||||||
} else {
|
|
||||||
// layer.builtin contains layer overrides - we can skip those
|
|
||||||
layerErrorCount.push(...this.validateLayer(layer, undefined, knownPaths, themeFile.id))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,19 +4,16 @@ import T from "./TestHelper";
|
||||||
import {FromJSON} from "../Customizations/JSON/FromJSON";
|
import {FromJSON} from "../Customizations/JSON/FromJSON";
|
||||||
import Locale from "../UI/i18n/Locale";
|
import Locale from "../UI/i18n/Locale";
|
||||||
import Translations from "../UI/i18n/Translations";
|
import Translations from "../UI/i18n/Translations";
|
||||||
import {UIEventSource} from "../Logic/UIEventSource";
|
|
||||||
import TagRenderingConfig from "../Customizations/JSON/TagRenderingConfig";
|
import TagRenderingConfig from "../Customizations/JSON/TagRenderingConfig";
|
||||||
import EditableTagRendering from "../UI/Popup/EditableTagRendering";
|
|
||||||
import {Translation} from "../UI/i18n/Translation";
|
import {Translation} from "../UI/i18n/Translation";
|
||||||
import {OH, OpeningHour} from "../UI/OpeningHours/OpeningHours";
|
import {OH, OpeningHour} from "../UI/OpeningHours/OpeningHours";
|
||||||
import PublicHolidayInput from "../UI/OpeningHours/PublicHolidayInput";
|
|
||||||
import {SubstitutedTranslation} from "../UI/SubstitutedTranslation";
|
|
||||||
import {Tag} from "../Logic/Tags/Tag";
|
import {Tag} from "../Logic/Tags/Tag";
|
||||||
import {And} from "../Logic/Tags/And";
|
import {And} from "../Logic/Tags/And";
|
||||||
|
import {Overpass} from "../Logic/Osm/Overpass";
|
||||||
|
|
||||||
Utils.runningFromConsole = true;
|
Utils.runningFromConsole = true;
|
||||||
|
|
||||||
export default class TagSpec extends T{
|
export default class TagSpec extends T {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super("Tags", [
|
super("Tags", [
|
||||||
|
@ -90,9 +87,9 @@ export default class TagSpec extends T{
|
||||||
equal(assign.matchesProperties({"some_key": "2021-03-29"}), false);
|
equal(assign.matchesProperties({"some_key": "2021-03-29"}), false);
|
||||||
|
|
||||||
const notEmptyList = FromJSON.Tag("xyz!~\\[\\]")
|
const notEmptyList = FromJSON.Tag("xyz!~\\[\\]")
|
||||||
equal(notEmptyList.matchesProperties({"xyz":undefined}), true);
|
equal(notEmptyList.matchesProperties({"xyz": undefined}), true);
|
||||||
equal(notEmptyList.matchesProperties({"xyz":"[]"}), false);
|
equal(notEmptyList.matchesProperties({"xyz": "[]"}), false);
|
||||||
equal(notEmptyList.matchesProperties({"xyz":"[\"abc\"]"}), true);
|
equal(notEmptyList.matchesProperties({"xyz": "[\"abc\"]"}), true);
|
||||||
|
|
||||||
|
|
||||||
})],
|
})],
|
||||||
|
@ -161,6 +158,38 @@ export default class TagSpec extends T{
|
||||||
equal(false, t.matchesProperties({"key": "somevalue"}))
|
equal(false, t.matchesProperties({"key": "somevalue"}))
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"Test not with overpass",
|
||||||
|
() => {
|
||||||
|
const t = {
|
||||||
|
and: [
|
||||||
|
"boundary=protected_area",
|
||||||
|
"protect_class!=98"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
const filter = FromJSON.Tag(t)
|
||||||
|
const overpass = filter.asOverpass();
|
||||||
|
console.log(overpass)
|
||||||
|
equal(overpass[0], "[\"boundary\"=\"protected_area\"][\"protect_class\"!~\"^98$\"]")
|
||||||
|
|
||||||
|
const or = {
|
||||||
|
or: [
|
||||||
|
"leisure=nature_reserve",
|
||||||
|
t
|
||||||
|
]
|
||||||
|
}
|
||||||
|
const overpassOr = FromJSON.Tag(or).asOverpass()
|
||||||
|
equal(2, overpassOr.length)
|
||||||
|
equal(overpassOr[1], "[\"boundary\"=\"protected_area\"][\"protect_class\"!~\"^98$\"]")
|
||||||
|
|
||||||
|
const orInOr = {or:[
|
||||||
|
"amenity=drinking_water",
|
||||||
|
or
|
||||||
|
]}
|
||||||
|
const overpassOrInor = FromJSON.Tag(orInOr).asOverpass()
|
||||||
|
equal(3, overpassOrInor.length)
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"Tagrendering test",
|
"Tagrendering test",
|
||||||
() => {
|
() => {
|
||||||
|
@ -358,27 +387,27 @@ export default class TagSpec extends T{
|
||||||
]);
|
]);
|
||||||
equal(rules, "Tu 10:00-12:00; Su 13:00-17:00");
|
equal(rules, "Tu 10:00-12:00; Su 13:00-17:00");
|
||||||
}],
|
}],
|
||||||
["JOIN OH with end hours", () =>{
|
["JOIN OH with end hours", () => {
|
||||||
const rules = OH.ToString(
|
const rules = OH.ToString(
|
||||||
OH.MergeTimes([
|
OH.MergeTimes([
|
||||||
|
|
||||||
{
|
{
|
||||||
weekday: 1,
|
weekday: 1,
|
||||||
endHour: 23,
|
endHour: 23,
|
||||||
endMinutes: 30,
|
endMinutes: 30,
|
||||||
startHour: 23,
|
startHour: 23,
|
||||||
startMinutes: 0
|
startMinutes: 0
|
||||||
}, {
|
}, {
|
||||||
weekday: 1,
|
weekday: 1,
|
||||||
endHour: 24,
|
endHour: 24,
|
||||||
endMinutes: 0,
|
endMinutes: 0,
|
||||||
startHour: 23,
|
startHour: 23,
|
||||||
startMinutes: 30
|
startMinutes: 30
|
||||||
},
|
},
|
||||||
|
|
||||||
]));
|
]));
|
||||||
equal(rules, "Tu 23:00-00:00");
|
equal(rules, "Tu 23:00-00:00");
|
||||||
}], ["JOIN OH with overflowed hours", () =>{
|
}], ["JOIN OH with overflowed hours", () => {
|
||||||
const rules = OH.ToString(
|
const rules = OH.ToString(
|
||||||
OH.MergeTimes([
|
OH.MergeTimes([
|
||||||
|
|
||||||
|
@ -464,7 +493,7 @@ export default class TagSpec extends T{
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const tagRendering = new TagRenderingConfig(config, null, "test");
|
const tagRendering = new TagRenderingConfig(config, null, "test");
|
||||||
equal(true, tagRendering.IsKnown({bottle: "yes"}))
|
equal(true, tagRendering.IsKnown({bottle: "yes"}))
|
||||||
equal(false, tagRendering.IsKnown({}))
|
equal(false, tagRendering.IsKnown({}))
|
||||||
}]]);
|
}]]);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue