forked from MapComplete/MapComplete
First steps to a real testing framework: first working version with mocha, chai and doctest-ts
This commit is contained in:
parent
edc366149b
commit
4f4fc650b1
42 changed files with 9032 additions and 9275 deletions
|
@ -1,140 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import SelectedElementTagsUpdater from "../Logic/Actors/SelectedElementTagsUpdater";
|
||||
import UserRelatedState from "../Logic/State/UserRelatedState";
|
||||
import {Utils} from "../Utils";
|
||||
import SelectedFeatureHandler from "../Logic/Actors/SelectedFeatureHandler";
|
||||
import {UIEventSource} from "../Logic/UIEventSource";
|
||||
import {ElementStorage} from "../Logic/ElementStorage";
|
||||
import Loc from "../Models/Loc";
|
||||
import * as bookcaseJson from "../assets/generated/themes/bookcases.json"
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
export default class ActorsSpec extends T {
|
||||
|
||||
constructor() {
|
||||
|
||||
const latestTags = {
|
||||
"amenity": "public_bookcase",
|
||||
"books": "children;adults",
|
||||
"capacity": "25",
|
||||
"description": "Deze boekenruilkast vindt je recht tegenover de Pim Pam Poem",
|
||||
"image:0": "https://i.imgur.com/Z8a69UG.jpg",
|
||||
"name": "Stubbekwartier-buurtbibliotheek",
|
||||
"nobrand": "yes",
|
||||
"opening_hours": "24/7",
|
||||
"operator": "Huisbewoner",
|
||||
"public_bookcase:type": "reading_box"
|
||||
}
|
||||
|
||||
Utils.injectJsonDownloadForTests(
|
||||
"https://www.openstreetmap.org/api/0.6/node/5568693115",
|
||||
{
|
||||
"version": "0.6",
|
||||
"generator": "CGImap 0.8.5 (1815943 spike-06.openstreetmap.org)",
|
||||
"copyright": "OpenStreetMap and contributors",
|
||||
"attribution": "http://www.openstreetmap.org/copyright",
|
||||
"license": "http://opendatacommons.org/licenses/odbl/1-0/",
|
||||
"elements": [{
|
||||
"type": "node",
|
||||
"id": 5568693115,
|
||||
"lat": 51.2179199,
|
||||
"lon": 3.2154662,
|
||||
"timestamp": "2021-08-21T16:22:55Z",
|
||||
"version": 6,
|
||||
"changeset": 110034454,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858,
|
||||
"tags": latestTags
|
||||
}]
|
||||
}
|
||||
)
|
||||
|
||||
super([
|
||||
[
|
||||
"download latest version",
|
||||
() => {
|
||||
const state = new UserRelatedState(new LayoutConfig(<any> bookcaseJson, true, "tests"))
|
||||
const feature = {
|
||||
"type": "Feature",
|
||||
"id": "node/5568693115",
|
||||
"properties": {
|
||||
"amenity": "public_bookcase",
|
||||
"books": "children;adults",
|
||||
"capacity": "25",
|
||||
"description": "Deze boekenruilkast vindt je recht tegenover de Pim Pam Poem",
|
||||
"image:0": "https://i.imgur.com/Z8a69UG.jpg",
|
||||
"name": "OUTDATED NAME",
|
||||
"nobrand": "yes",
|
||||
"opening_hours": "24/7",
|
||||
"operator": "Huisbewoner",
|
||||
"public_bookcase:type": "reading_box",
|
||||
"id": "node/5568693115",
|
||||
"_lat": "51.2179199",
|
||||
"_lon": "3.2154662",
|
||||
"fixme": "SOME FIXME"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
3.2154662,
|
||||
51.2179199
|
||||
]
|
||||
},
|
||||
"bbox": {
|
||||
"maxLat": 51.2179199,
|
||||
"maxLon": 3.2154662,
|
||||
"minLat": 51.2179199,
|
||||
"minLon": 3.2154662
|
||||
},
|
||||
"_lon": 3.2154662,
|
||||
"_lat": 51.2179199
|
||||
}
|
||||
state.allElements.addOrGetElement(feature)
|
||||
SelectedElementTagsUpdater.installCallback(state)
|
||||
|
||||
// THis should trigger a download of the latest feaures and update the tags
|
||||
// However, this doesn't work with ts-node for some reason
|
||||
state.selectedElement.setData(feature)
|
||||
|
||||
SelectedElementTagsUpdater.applyUpdate(state, latestTags, feature.properties.id)
|
||||
|
||||
// The name should be updated
|
||||
T.equals("Stubbekwartier-buurtbibliotheek", feature.properties.name)
|
||||
// The fixme should be removed
|
||||
T.equals(undefined, feature.properties.fixme)
|
||||
|
||||
}],
|
||||
["Hash without selected element should download geojson from OSM-API", async () => {
|
||||
const hash = new UIEventSource("node/5568693115")
|
||||
const selected = new UIEventSource(undefined)
|
||||
const loc = new UIEventSource<Loc>({
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
zoom: 0
|
||||
})
|
||||
|
||||
|
||||
loc.addCallback(_ => {
|
||||
T.equals("node/5568693115", selected.data.properties.id)
|
||||
T.equals(14, loc.data.zoom)
|
||||
T.equals(51.2179199, loc.data.lat)
|
||||
})
|
||||
|
||||
new SelectedFeatureHandler(hash, {
|
||||
selectedElement: selected,
|
||||
allElements: new ElementStorage(),
|
||||
featurePipeline: undefined,
|
||||
locationControl: loc,
|
||||
layoutToUse: undefined
|
||||
})
|
||||
|
||||
|
||||
}]
|
||||
|
||||
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import {Changes} from "../Logic/Osm/Changes";
|
||||
import {ChangeDescription, ChangeDescriptionTools} from "../Logic/Osm/Actions/ChangeDescription";
|
||||
|
||||
export default class ChangesSpec extends T {
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
["Generate preXML from changeDescriptions", () => {
|
||||
const changeDescrs: ChangeDescription[] = [
|
||||
{
|
||||
type: "node",
|
||||
id: -1,
|
||||
changes: {
|
||||
lat: 42,
|
||||
lon: -8
|
||||
},
|
||||
tags: [{k: "someKey", v: "someValue"}],
|
||||
meta: {
|
||||
changeType: "create",
|
||||
theme: "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "node",
|
||||
id: -1,
|
||||
tags: [{k: 'foo', v: 'bar'}],
|
||||
meta: {
|
||||
changeType: "answer",
|
||||
theme: "test"
|
||||
}
|
||||
}
|
||||
]
|
||||
const c = new Changes()
|
||||
const descr = c.CreateChangesetObjects(
|
||||
changeDescrs,
|
||||
[]
|
||||
)
|
||||
T.equals(0, descr.modifiedObjects.length)
|
||||
T.equals(0, descr.deletedObjects.length)
|
||||
T.equals(1, descr.newObjects.length)
|
||||
const ch = descr.newObjects[0]
|
||||
T.equals("bar", ch.tags["foo"])
|
||||
T.equals("someValue", ch.tags["someKey"])
|
||||
}]
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,181 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import {ChangesetHandler, ChangesetTag} from "../Logic/Osm/ChangesetHandler";
|
||||
import {UIEventSource} from "../Logic/UIEventSource";
|
||||
import {OsmConnection} from "../Logic/Osm/OsmConnection";
|
||||
import {ElementStorage} from "../Logic/ElementStorage";
|
||||
import {Changes} from "../Logic/Osm/Changes";
|
||||
|
||||
export default class ChangesetHandlerSpec extends T {
|
||||
|
||||
private static asDict(tags: {key: string, value: string | number}[]) : Map<string, string | number>{
|
||||
const d= new Map<string, string | number>()
|
||||
|
||||
for (const tag of tags) {
|
||||
d.set(tag.key, tag.value)
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
[
|
||||
"Test rewrite tags", () => {
|
||||
const cs = new ChangesetHandler(new UIEventSource<boolean>(true),
|
||||
new OsmConnection({}),
|
||||
new ElementStorage(),
|
||||
new Changes(),
|
||||
new UIEventSource(undefined)
|
||||
);
|
||||
|
||||
|
||||
const oldChangesetMeta = {
|
||||
"type": "changeset",
|
||||
"id": 118443748,
|
||||
"created_at": "2022-03-13T19:52:10Z",
|
||||
"closed_at": "2022-03-13T20:54:35Z",
|
||||
"open": false,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858,
|
||||
"minlat": 51.0361902,
|
||||
"minlon": 3.7092939,
|
||||
"maxlat": 51.0364194,
|
||||
"maxlon": 3.7099520,
|
||||
"comments_count": 0,
|
||||
"changes_count": 3,
|
||||
"tags": {
|
||||
"answer": "5",
|
||||
"comment": "Adding data with #MapComplete for theme #toerisme_vlaanderen",
|
||||
"created_by": "MapComplete 0.16.6",
|
||||
"host": "https://mapcomplete.osm.be/toerisme_vlaanderen.html",
|
||||
"imagery": "osm",
|
||||
"locale": "nl",
|
||||
"source": "survey",
|
||||
"source:node/-1":"note/1234",
|
||||
"theme": "toerisme_vlaanderen",
|
||||
}
|
||||
}
|
||||
let rewritten = cs.RewriteTagsOf(
|
||||
[{
|
||||
key: "newTag",
|
||||
value: "newValue",
|
||||
aggregate: false
|
||||
}],
|
||||
new Map<string, string>(),
|
||||
oldChangesetMeta)
|
||||
let d = ChangesetHandlerSpec.asDict(rewritten)
|
||||
T.equals(10, d.size)
|
||||
T.equals("5", d.get("answer"))
|
||||
T.equals("Adding data with #MapComplete for theme #toerisme_vlaanderen", d.get("comment"))
|
||||
T.equals("MapComplete 0.16.6", d.get("created_by"))
|
||||
T.equals("https://mapcomplete.osm.be/toerisme_vlaanderen.html", d.get("host"))
|
||||
T.equals("osm", d.get("imagery"))
|
||||
T.equals("survey", d.get("source"))
|
||||
T.equals("note/1234", d.get("source:node/-1"))
|
||||
T.equals("toerisme_vlaanderen", d.get("theme"))
|
||||
|
||||
T.equals("newValue", d.get("newTag"))
|
||||
|
||||
|
||||
|
||||
|
||||
rewritten = cs.RewriteTagsOf(
|
||||
[{
|
||||
key: "answer",
|
||||
value: "37",
|
||||
aggregate: true
|
||||
}],
|
||||
new Map<string, string>(),
|
||||
oldChangesetMeta)
|
||||
d = ChangesetHandlerSpec.asDict(rewritten)
|
||||
|
||||
T.equals(9, d.size)
|
||||
T.equals("42", d.get("answer"))
|
||||
T.equals("Adding data with #MapComplete for theme #toerisme_vlaanderen", d.get("comment"))
|
||||
T.equals("MapComplete 0.16.6", d.get("created_by"))
|
||||
T.equals("https://mapcomplete.osm.be/toerisme_vlaanderen.html", d.get("host"))
|
||||
T.equals("osm", d.get("imagery"))
|
||||
T.equals("survey", d.get("source"))
|
||||
T.equals("note/1234", d.get("source:node/-1"))
|
||||
T.equals("toerisme_vlaanderen", d.get("theme"))
|
||||
|
||||
rewritten = cs.RewriteTagsOf(
|
||||
[],
|
||||
new Map<string, string>([["node/-1", "node/42"]]),
|
||||
oldChangesetMeta)
|
||||
d = ChangesetHandlerSpec.asDict(rewritten)
|
||||
|
||||
T.equals(9, d.size)
|
||||
T.equals("5", d.get("answer"))
|
||||
T.equals("Adding data with #MapComplete for theme #toerisme_vlaanderen", d.get("comment"))
|
||||
T.equals("MapComplete 0.16.6", d.get("created_by"))
|
||||
T.equals("https://mapcomplete.osm.be/toerisme_vlaanderen.html", d.get("host"))
|
||||
T.equals("osm", d.get("imagery"))
|
||||
T.equals("survey", d.get("source"))
|
||||
T.equals("note/1234", d.get("source:node/42"))
|
||||
T.equals("toerisme_vlaanderen", d.get("theme"))
|
||||
|
||||
},
|
||||
],[
|
||||
"Test rewrite on special motivation", () => {
|
||||
|
||||
|
||||
const cs = new ChangesetHandler(new UIEventSource<boolean>(true),
|
||||
new OsmConnection({}),
|
||||
new ElementStorage(),
|
||||
new Changes(),
|
||||
new UIEventSource(undefined)
|
||||
);
|
||||
|
||||
|
||||
const oldChangesetMeta = {
|
||||
"type": "changeset",
|
||||
"id": 118443748,
|
||||
"created_at": "2022-03-13T19:52:10Z",
|
||||
"closed_at": "2022-03-13T20:54:35Z",
|
||||
"open": false,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858,
|
||||
"minlat": 51.0361902,
|
||||
"minlon": 3.7092939,
|
||||
"maxlat": 51.0364194,
|
||||
"maxlon": 3.7099520,
|
||||
"comments_count": 0,
|
||||
"changes_count": 3,
|
||||
"tags": {
|
||||
"answer": "5",
|
||||
"comment": "Adding data with #MapComplete for theme #toerisme_vlaanderen",
|
||||
"created_by": "MapComplete 0.16.6",
|
||||
"host": "https://mapcomplete.osm.be/toerisme_vlaanderen.html",
|
||||
"imagery": "osm",
|
||||
"locale": "nl",
|
||||
"source": "survey",
|
||||
"source:-1":"note/1234",
|
||||
"theme": "toerisme_vlaanderen",
|
||||
}
|
||||
}
|
||||
|
||||
const extraMetaTags : ChangesetTag[] = [
|
||||
{
|
||||
key: "created_by",
|
||||
value:"mapcomplete"
|
||||
},
|
||||
{
|
||||
key: "source:node/-1",
|
||||
value:"note/1234"
|
||||
}
|
||||
]
|
||||
const changes = new Map<string, string>([["node/-1","node/42"]])
|
||||
const hasSpecialMotivationChanges = ChangesetHandler.rewriteMetaTags(extraMetaTags, changes)
|
||||
T.isTrue(hasSpecialMotivationChanges, "Special rewrite did not trigger")
|
||||
// Rewritten inline by rewriteMetaTags
|
||||
T.equals("source:node/42", extraMetaTags[1].key)
|
||||
T.equals("note/1234", extraMetaTags[1].value)
|
||||
T.equals("created_by", extraMetaTags[0].key)
|
||||
T.equals("mapcomplete", extraMetaTags[0].value)
|
||||
}
|
||||
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import {exec} from "child_process";
|
||||
|
||||
export default class CodeQualitySpec extends T {
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
[
|
||||
"no constructor.name in compiled code", () => {
|
||||
CodeQualitySpec.detectInCode("constructor\\.name", "This is not allowed, as minification does erase names.")
|
||||
}],
|
||||
[
|
||||
"no reverse in compiled code", () => {
|
||||
CodeQualitySpec.detectInCode("reverse()", "Reverse is stateful and changes the source list. This often causes subtle bugs")
|
||||
}]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param forbidden: a GREP-regex. This means that '.' is a wildcard and should be escaped to match a literal dot
|
||||
* @param reason
|
||||
* @private
|
||||
*/
|
||||
private static detectInCode(forbidden: string, reason: string) {
|
||||
|
||||
const excludedDirs = [".git", "node_modules", "dist", ".cache", ".parcel-cache", "assets"]
|
||||
|
||||
exec("grep -n \"" + forbidden + "\" -r . " + excludedDirs.map(d => "--exclude-dir=" + d).join(" "), ((error, stdout, stderr) => {
|
||||
if (error?.message?.startsWith("Command failed: grep")) {
|
||||
console.warn("Command failed!")
|
||||
return;
|
||||
}
|
||||
if (error !== null) {
|
||||
throw error
|
||||
|
||||
}
|
||||
if (stderr !== "") {
|
||||
throw stderr
|
||||
}
|
||||
|
||||
const found = stdout.split("\n").filter(s => s !== "").filter(s => !s.startsWith("./test/"));
|
||||
if (found.length > 0) {
|
||||
throw `Found a '${forbidden}' at \n ${found.join("\n ")}.\n ${reason}`
|
||||
}
|
||||
|
||||
}))
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -1,35 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import CreateNoteImportLayer from "../Models/ThemeConfig/Conversion/CreateNoteImportLayer";
|
||||
import * as bookcases from "../assets/layers/public_bookcase/public_bookcase.json"
|
||||
import {DesugaringContext} from "../Models/ThemeConfig/Conversion/Conversion";
|
||||
import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson";
|
||||
import {TagRenderingConfigJson} from "../Models/ThemeConfig/Json/TagRenderingConfigJson";
|
||||
import {PrepareLayer} from "../Models/ThemeConfig/Conversion/PrepareLayer";
|
||||
import {Utils} from "../Utils";
|
||||
|
||||
export default class CreateNoteImportLayerSpec extends T {
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
["Bookcase", () => {
|
||||
const desugaringState: DesugaringContext = {
|
||||
sharedLayers: new Map<string, LayerConfigJson>(),
|
||||
tagRenderings: new Map<string, TagRenderingConfigJson>()
|
||||
|
||||
}
|
||||
const layerPrepare = new PrepareLayer(desugaringState)
|
||||
const layer = layerPrepare.convertStrict(bookcases, "ImportLayerGeneratorTest:Parse bookcases")
|
||||
const generator = new CreateNoteImportLayer()
|
||||
const generatedLayer: LayerConfigJson = generator.convertStrict(layer, "ImportLayerGeneratorTest: convert")
|
||||
T.equals("_tags~(^|.*;)amenity=public_bookcase($|;.*)", generatedLayer.isShown.mappings[1].if["and"][1].or[0].and[0])
|
||||
T.isTrue(generatedLayer.minzoom <= layer.minzoom, "Zoomlevel is to high")
|
||||
let renderings = Utils.NoNull(Utils.NoNull(generatedLayer.tagRenderings
|
||||
.map(tr => (<TagRenderingConfigJson>tr).render))
|
||||
.map(render => render["en"]))
|
||||
T.isTrue(renderings.some(r => r.indexOf("import_button") > 0), "no import button found")
|
||||
}]
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,450 +0,0 @@
|
|||
import * as Assert from "assert";
|
||||
import {equal} from "assert";
|
||||
import T from "./TestHelper";
|
||||
import {GeoOperations} from "../Logic/GeoOperations";
|
||||
import {BBox} from "../Logic/BBox";
|
||||
import * as turf from "@turf/turf"
|
||||
|
||||
export default class GeoOperationsSpec extends T {
|
||||
|
||||
private static polygon = {
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
1.8017578124999998,
|
||||
50.401515322782366
|
||||
],
|
||||
[
|
||||
-3.1640625,
|
||||
46.255846818480315
|
||||
],
|
||||
[
|
||||
5.185546875,
|
||||
44.74673324024678
|
||||
],
|
||||
[
|
||||
1.8017578124999998,
|
||||
50.401515322782366
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
};
|
||||
private static multiPolygon = {
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [[
|
||||
[
|
||||
[
|
||||
1.8017578124999998,
|
||||
50.401515322782366
|
||||
],
|
||||
[
|
||||
-3.1640625,
|
||||
46.255846818480315
|
||||
],
|
||||
[
|
||||
5.185546875,
|
||||
44.74673324024678
|
||||
],
|
||||
[
|
||||
1.8017578124999998,
|
||||
50.401515322782366
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
1.0107421875,
|
||||
48.821332549646634
|
||||
],
|
||||
[
|
||||
1.329345703125,
|
||||
48.25394114463431
|
||||
],
|
||||
[
|
||||
1.988525390625,
|
||||
48.71271258145237
|
||||
],
|
||||
[
|
||||
0.999755859375,
|
||||
48.86471476180277
|
||||
],
|
||||
[
|
||||
1.0107421875,
|
||||
48.821332549646634
|
||||
]
|
||||
]
|
||||
]]
|
||||
}
|
||||
};
|
||||
|
||||
private static inHole = [1.42822265625, 48.61838518688487]
|
||||
private static inMultiPolygon = [2.515869140625, 47.37603463349758]
|
||||
private static outsidePolygon = [4.02099609375, 47.81315451752768]
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
["Point out of polygon", () => {
|
||||
GeoOperationsSpec.isFalse(GeoOperations.inside([
|
||||
3.779296875,
|
||||
48.777912755501845
|
||||
], GeoOperationsSpec.polygon), "Point is outside of the polygon");
|
||||
}
|
||||
|
||||
],
|
||||
["Point inside of polygon", () => {
|
||||
|
||||
GeoOperationsSpec.isTrue(GeoOperations.inside([
|
||||
1.23046875,
|
||||
47.60616304386874
|
||||
], GeoOperationsSpec.polygon), "Point is inside of the polygon");
|
||||
}
|
||||
],
|
||||
["MultiPolygonTest", () => {
|
||||
|
||||
const isTrue = GeoOperationsSpec.isTrue;
|
||||
const isFalse = GeoOperationsSpec.isFalse;
|
||||
|
||||
isFalse(GeoOperations.inside(GeoOperationsSpec.inHole, GeoOperationsSpec.multiPolygon), "InHole was detected as true");
|
||||
isTrue(GeoOperations.inside(GeoOperationsSpec.inMultiPolygon, GeoOperationsSpec.multiPolygon), "InMultiPolgyon was not detected as true");
|
||||
isFalse(GeoOperations.inside(GeoOperationsSpec.outsidePolygon, GeoOperationsSpec.multiPolygon), "OutsideOfPolygon was detected as true");
|
||||
|
||||
}],
|
||||
["Intersection between a line and a polygon", () => {
|
||||
const line = {
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"type": "LineString",
|
||||
"coordinates": [
|
||||
[
|
||||
3.779296875,
|
||||
48.777912755501845
|
||||
],
|
||||
[
|
||||
1.23046875,
|
||||
47.60616304386874
|
||||
]
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const overlap = GeoOperations.calculateOverlap(line, [GeoOperationsSpec.polygon]);
|
||||
Assert.equal(1, overlap.length)
|
||||
}],
|
||||
["Fully enclosed", () => {
|
||||
const line = {
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"type": "LineString",
|
||||
"coordinates": [
|
||||
[
|
||||
0.0439453125,
|
||||
47.31648293428332
|
||||
],
|
||||
[
|
||||
0.6591796875,
|
||||
46.77749276376827
|
||||
]
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const overlap = GeoOperations.calculateOverlap(line, [GeoOperationsSpec.polygon]);
|
||||
Assert.equal(1, overlap.length)
|
||||
}],
|
||||
["overlapWith matches points too", () => {
|
||||
const point = {
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
2.274169921875,
|
||||
46.76244305208004
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const overlap = GeoOperations.calculateOverlap(point, [GeoOperationsSpec.polygon]);
|
||||
Assert.equal(1, overlap.length)
|
||||
}],
|
||||
["bbox bounds test",
|
||||
() => {
|
||||
const bbox = BBox.fromTile(16, 32754, 21785)
|
||||
equal(-0.076904296875, bbox.minLon)
|
||||
equal(-0.0714111328125, bbox.maxLon)
|
||||
equal(51.5292513551899, bbox.minLat)
|
||||
equal(51.53266860674158, bbox.maxLat)
|
||||
}
|
||||
],
|
||||
["Regression test: intersection/overlap", () => {
|
||||
|
||||
const polyGrb = {
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"osm_id": "25189153",
|
||||
"size_grb_building": "217.14",
|
||||
"addr:housenumber": "173",
|
||||
"addr:street": "Kortrijksestraat",
|
||||
"building": "house",
|
||||
"source:geometry:entity": "Gbg",
|
||||
"source:geometry:date": "2015/02/27",
|
||||
"source:geometry:oidn": "1729460",
|
||||
"source:geometry:uidn": "8713648",
|
||||
"H_DTM_MIN": "17.28",
|
||||
"H_DTM_GEM": "17.59",
|
||||
"H_DSM_MAX": "29.04",
|
||||
"H_DSM_P99": "28.63",
|
||||
"HN_MAX": "11.45",
|
||||
"HN_P99": "11.04",
|
||||
"detection_method": "from existing OSM building source: house ,hits (3)",
|
||||
"auto_building": "house",
|
||||
"size_shared": "210.68",
|
||||
"size_source_building": "212.63",
|
||||
"id": "https://betadata.grbosm.site/grb?bbox=360935.6475626023,6592540.815539878,361088.52161917265,6592693.689596449/37",
|
||||
"_lat": "50.83736194999996",
|
||||
"_lon": "3.2432137000000116",
|
||||
"_layer": "GRB",
|
||||
"_length": "48.51529464293261",
|
||||
"_length:km": "0.0",
|
||||
"_now:date": "2021-12-05",
|
||||
"_now:datetime": "2021-12-05 21:51:40",
|
||||
"_loaded:date": "2021-12-05",
|
||||
"_loaded:datetime": "2021-12-05 21:51:40"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
3.2431059999999974,
|
||||
50.83730270000021
|
||||
],
|
||||
[
|
||||
3.243174299999987,
|
||||
50.83728850000007
|
||||
],
|
||||
[
|
||||
3.2432116000000173,
|
||||
50.83736910000003
|
||||
],
|
||||
[
|
||||
3.2433214000000254,
|
||||
50.83740350000011
|
||||
],
|
||||
[
|
||||
3.24329779999996,
|
||||
50.837435399999855
|
||||
],
|
||||
[
|
||||
3.2431881000000504,
|
||||
50.83740090000025
|
||||
],
|
||||
[
|
||||
3.243152699999997,
|
||||
50.83738980000017
|
||||
],
|
||||
[
|
||||
3.2431059999999974,
|
||||
50.83730270000021
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
"id": "https://betadata.grbosm.site/grb?bbox=360935.6475626023,6592540.815539878,361088.52161917265,6592693.689596449/37",
|
||||
"_lon": 3.2432137000000116,
|
||||
"_lat": 50.83736194999996,
|
||||
"bbox": {
|
||||
"maxLat": 50.837435399999855,
|
||||
"maxLon": 3.2433214000000254,
|
||||
"minLat": 50.83728850000007,
|
||||
"minLon": 3.2431059999999974
|
||||
}
|
||||
}
|
||||
const polyHouse = {
|
||||
"type": "Feature",
|
||||
"id": "way/594963177",
|
||||
"properties": {
|
||||
"timestamp": "2021-12-05T04:04:55Z",
|
||||
"version": 3,
|
||||
"changeset": 114571409,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858,
|
||||
"addr:housenumber": "171",
|
||||
"addr:street": "Kortrijksestraat",
|
||||
"building": "house",
|
||||
"source:geometry:date": "2018-10-22",
|
||||
"source:geometry:ref": "Gbg/5096537",
|
||||
"_last_edit:contributor": "Pieter Vander Vennet",
|
||||
"_last_edit:contributor:uid": 3818858,
|
||||
"_last_edit:changeset": 114571409,
|
||||
"_last_edit:timestamp": "2021-12-05T04:04:55Z",
|
||||
"_version_number": 3,
|
||||
"id": "way/594963177",
|
||||
"_backend": "https://www.openstreetmap.org",
|
||||
"_lat": "50.83736395",
|
||||
"_lon": "3.2430937",
|
||||
"_layer": "OSM-buildings",
|
||||
"_length": "43.561938680928506",
|
||||
"_length:km": "0.0",
|
||||
"_now:date": "2021-12-05",
|
||||
"_now:datetime": "2021-12-05 21:51:40",
|
||||
"_loaded:date": "2021-12-05",
|
||||
"_loaded:datetime": "2021-12-05 21:51:39",
|
||||
"_surface": "93.32785810484549",
|
||||
"_surface:ha": "0"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
3.2429993,
|
||||
50.8373243
|
||||
],
|
||||
[
|
||||
3.243106,
|
||||
50.8373027
|
||||
],
|
||||
[
|
||||
3.2431527,
|
||||
50.8373898
|
||||
],
|
||||
[
|
||||
3.2431881,
|
||||
50.8374009
|
||||
],
|
||||
[
|
||||
3.2431691,
|
||||
50.8374252
|
||||
],
|
||||
[
|
||||
3.2430936,
|
||||
50.837401
|
||||
],
|
||||
[
|
||||
3.243046,
|
||||
50.8374112
|
||||
],
|
||||
[
|
||||
3.2429993,
|
||||
50.8373243
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
"_lon": 3.2430937,
|
||||
"_lat": 50.83736395,
|
||||
"bbox": {
|
||||
"maxLat": 50.8374252,
|
||||
"maxLon": 3.2431881,
|
||||
"minLat": 50.8373027,
|
||||
"minLon": 3.2429993
|
||||
}
|
||||
}
|
||||
|
||||
const p0 = turf.polygon(polyGrb.geometry.coordinates)
|
||||
Assert.notEqual(p0, null)
|
||||
const p1 = turf.polygon(polyHouse.geometry.coordinates)
|
||||
Assert.notEqual(p1, null)
|
||||
|
||||
const overlaps = GeoOperations.calculateOverlap(polyGrb, [polyHouse])
|
||||
Assert.equal(overlaps.length, 0)
|
||||
const overlapsRev = GeoOperations.calculateOverlap(polyHouse, [polyGrb])
|
||||
Assert.equal(overlapsRev.length, 0)
|
||||
|
||||
}],
|
||||
["Overnode removal test", () => {
|
||||
|
||||
const feature = {
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
4.477944199999975,
|
||||
51.02783550000022
|
||||
],
|
||||
[
|
||||
4.477987899999996,
|
||||
51.027818800000034
|
||||
],
|
||||
[
|
||||
4.478004500000021,
|
||||
51.02783399999988
|
||||
],
|
||||
[
|
||||
4.478025499999962,
|
||||
51.02782489999994
|
||||
],
|
||||
[
|
||||
4.478079099999993,
|
||||
51.027873899999896
|
||||
],
|
||||
[
|
||||
4.47801040000006,
|
||||
51.027903799999955
|
||||
],
|
||||
[
|
||||
4.477964799999972,
|
||||
51.02785709999982
|
||||
],
|
||||
[
|
||||
4.477964699999964,
|
||||
51.02785690000006
|
||||
],
|
||||
[
|
||||
4.477944199999975,
|
||||
51.02783550000022
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
const copy = GeoOperations.removeOvernoding(feature)
|
||||
Assert.equal(copy.geometry.coordinates[0].length, 7)
|
||||
T.listIdentical([
|
||||
[
|
||||
4.477944199999975,
|
||||
51.02783550000022
|
||||
],
|
||||
[
|
||||
4.477987899999996,
|
||||
51.027818800000034
|
||||
],
|
||||
[
|
||||
4.478004500000021,
|
||||
51.02783399999988
|
||||
],
|
||||
[
|
||||
4.478025499999962,
|
||||
51.02782489999994
|
||||
],
|
||||
[
|
||||
4.478079099999993,
|
||||
51.027873899999896
|
||||
],
|
||||
[
|
||||
4.47801040000006,
|
||||
51.027903799999955
|
||||
],
|
||||
[
|
||||
4.477944199999975,
|
||||
51.02783550000022
|
||||
]
|
||||
], copy.geometry.coordinates[0])
|
||||
}]
|
||||
]
|
||||
)
|
||||
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
import {equal} from "assert";
|
||||
import T from "./TestHelper";
|
||||
import {Translation} from "../UI/i18n/Translation";
|
||||
import * as cyclofix from "../assets/generated/themes/cyclofix.json"
|
||||
import {ExtractImages} from "../Models/ThemeConfig/Conversion/FixImages";
|
||||
|
||||
export default class ImageAttributionSpec extends T {
|
||||
constructor() {
|
||||
super([
|
||||
[
|
||||
"Should find all the images",
|
||||
() => {
|
||||
const images = new Set(new ExtractImages(true, new Map<string, any>()).convertStrict(<any> cyclofix, "test"))
|
||||
const expectedValues = [
|
||||
'./assets/layers/bike_repair_station/repair_station.svg',
|
||||
'./assets/layers/bike_repair_station/repair_station_pump.svg',
|
||||
'./assets/layers/bike_repair_station/broken_pump.svg',
|
||||
'./assets/layers/bike_repair_station/pump.svg',
|
||||
'./assets/themes/cyclofix/fietsambassade_gent_logo_small.svg',
|
||||
'./assets/layers/bike_repair_station/pump_example_manual.jpg',
|
||||
'./assets/layers/bike_repair_station/pump_example.png',
|
||||
'./assets/layers/bike_repair_station/pump_example_round.jpg',
|
||||
'./assets/layers/bike_repair_station/repair_station_example_2.jpg',
|
||||
'close']
|
||||
for (const expected of expectedValues) {
|
||||
T.isTrue(images.has(expected), expected + " not found")
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
"Test image discovery regex",
|
||||
() => {
|
||||
const tr = new Translation({en: "XYZ <img src='a.svg'/> XYZ <img src=\"some image.svg\"></img> XYZ <img src=b.svg/>"})
|
||||
const images = new Set<string>(tr.ExtractImages(false));
|
||||
equal(3, images.size)
|
||||
T.isTrue(images.has("a.svg"), "a.svg not found")
|
||||
T.isTrue(images.has("b.svg"), "b.svg not found")
|
||||
T.isTrue(images.has("some image.svg"), "some image.svg not found")
|
||||
|
||||
}
|
||||
]
|
||||
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import AllImageProviders from "../Logic/ImageProviders/AllImageProviders";
|
||||
import {UIEventSource} from "../Logic/UIEventSource";
|
||||
import {Utils} from "../Utils";
|
||||
|
||||
export default class ImageProviderSpec extends T {
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
["Search images", () => {
|
||||
|
||||
let i = 0
|
||||
|
||||
function expects(url, tags, providerName = undefined) {
|
||||
tags.id = "test/" + i
|
||||
i++
|
||||
AllImageProviders.LoadImagesFor(new UIEventSource(tags)).addCallbackD(images => {
|
||||
console.log("ImageProvider test", tags.id, "for", tags)
|
||||
const img = images[0]
|
||||
if (img === undefined) {
|
||||
throw "No image found"
|
||||
}
|
||||
T.equals(url, img.url, tags.id)
|
||||
if (providerName) {
|
||||
T.equals(img.provider.constructor.name, providerName)
|
||||
}
|
||||
console.log("OK")
|
||||
})
|
||||
}
|
||||
|
||||
const muntpoort_expected = "https://commons.wikimedia.org/wiki/Special:FilePath/File%3ABr%C3%BCgge-Muntpoort_6-29510-58192.jpg?width=500&height=400"
|
||||
expects(
|
||||
muntpoort_expected,
|
||||
{
|
||||
"wikimedia_commons": "File:Brügge-Muntpoort_6-29510-58192.jpg"
|
||||
}, "WikimediaImageProvider")
|
||||
|
||||
|
||||
expects(muntpoort_expected,
|
||||
{
|
||||
"wikimedia_commons": "https://upload.wikimedia.org/wikipedia/commons/c/cd/Br%C3%BCgge-Muntpoort_6-29510-58192.jpg"
|
||||
}, "WikimediaImageProvider")
|
||||
|
||||
expects(muntpoort_expected, {
|
||||
"image": "https://upload.wikimedia.org/wikipedia/commons/c/cd/Br%C3%BCgge-Muntpoort_6-29510-58192.jpg"
|
||||
}, "WikimediaImageProvider")
|
||||
|
||||
|
||||
expects("https://commons.wikimedia.org/wiki/Special:FilePath/File%3ABelgium-5955_-_Simon_Stevin_(13746657193).jpg?width=500&height=400", {
|
||||
"image": "File:Belgium-5955_-_Simon_Stevin_(13746657193).jpg"
|
||||
}, "WikimediaImageProvider")
|
||||
|
||||
expects("https://commons.wikimedia.org/wiki/Special:FilePath/File%3ABelgium-5955_-_Simon_Stevin_(13746657193).jpg?width=500&height=400", {
|
||||
"wikimedia_commons": "File:Belgium-5955_-_Simon_Stevin_(13746657193).jpg"
|
||||
}, "WikimediaImageProvider")
|
||||
|
||||
|
||||
expects("https://commons.wikimedia.org/wiki/Special:FilePath/File%3ABrugge_Leeuwstraat_zonder_nummer_Leeuwbrug_-_119334_-_onroerenderfgoed.jpg?width=500&height=400", {
|
||||
image: "File:Brugge_Leeuwstraat_zonder_nummer_Leeuwbrug_-_119334_-_onroerenderfgoed.jpg"
|
||||
}, "WikimediaImageProvider")
|
||||
|
||||
expects("https://commons.wikimedia.org/wiki/Special:FilePath/File%3APapageno_Jef_Claerhout.jpg?width=500&height=400", {
|
||||
"wikimedia_commons": "File:Papageno_Jef_Claerhout.jpg"
|
||||
}, "WikimediaImageProvider")
|
||||
|
||||
Utils.injectJsonDownloadForTests(
|
||||
"https://graph.mapillary.com/196804715753265?fields=thumb_1024_url&&access_token=MLY|4441509239301885|b40ad2d3ea105435bd40c7e76993ae85",
|
||||
{
|
||||
"thumb_1024_url": "https://scontent-bru2-1.xx.fbcdn.net/m1/v/t6/An8HQ3DrfU76tWMC602spvM_e_rqOHyiUcYUTetXM7K52DDBEY5J4FWg4WKQqVUlMsWJn4nLXk0pxlBLx31146FqZ2Kg65z7lJUfR6wpW6WPSR5_y7RKdv4YEuzPjwIN0lagBnQONV3UjmXnEGpMouU?stp=s1024x768&ccb=10-5&oh=d460b401c505714ee1cb8bd6baf8ae5d&oe=61731FC3&_nc_sid=122ab1",
|
||||
"id": "196804715753265"
|
||||
}
|
||||
)
|
||||
|
||||
expects("https://scontent-bru2-1.xx.fbcdn.net/m1/v/t6/An8HQ3DrfU76tWMC602spvM_e_rqOHyiUcYUTetXM7K52DDBEY5J4FWg4WKQqVUlMsWJn4nLXk0pxlBLx31146FqZ2Kg65z7lJUfR6wpW6WPSR5_y7RKdv4YEuzPjwIN0lagBnQONV3UjmXnEGpMouU?stp=s1024x768&ccb=10-5&oh=d460b401c505714ee1cb8bd6baf8ae5d&oe=61731FC3&_nc_sid=122ab1", {
|
||||
"mapillary": "https://www.mapillary.com/app/?pKey=196804715753265"
|
||||
})
|
||||
|
||||
|
||||
}]
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,219 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import CreateMultiPolygonWithPointReuseAction from "../Logic/Osm/Actions/CreateMultiPolygonWithPointReuseAction";
|
||||
import { Tag } from "../Logic/Tags/Tag";
|
||||
import FeaturePipelineState from "../Logic/State/FeaturePipelineState";
|
||||
import { Changes } from "../Logic/Osm/Changes";
|
||||
import {ChangesetHandler} from "../Logic/Osm/ChangesetHandler";
|
||||
import * as Assert from "assert";
|
||||
|
||||
export default class ImportMultiPolygonSpec extends T {
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
["Correct changeset",
|
||||
async () => {
|
||||
|
||||
const feature = {
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"osm_id": "41097039",
|
||||
"size_grb_building": "1374.89",
|
||||
"addr:housenumber": "53",
|
||||
"addr:street": "Startelstraat",
|
||||
"building": "house",
|
||||
"source:geometry:entity": "Gbg",
|
||||
"source:geometry:date": "2014-04-28",
|
||||
"source:geometry:oidn": "150044",
|
||||
"source:geometry:uidn": "5403181",
|
||||
"H_DTM_MIN": "50.35",
|
||||
"H_DTM_GEM": "50.97",
|
||||
"H_DSM_MAX": "59.40",
|
||||
"H_DSM_P99": "59.09",
|
||||
"HN_MAX": "8.43",
|
||||
"HN_P99": "8.12",
|
||||
"detection_method": "derived from OSM landuse: farmyard",
|
||||
"auto_target_landuse": "farmyard",
|
||||
"size_source_landuse": "8246.28",
|
||||
"auto_building": "farm",
|
||||
"id": "41097039",
|
||||
"_lat": "50.84633355000016",
|
||||
"_lon": "5.262964150000011",
|
||||
"_layer": "grb",
|
||||
"_length": "185.06002152312757",
|
||||
"_length:km": "0.2",
|
||||
"_now:date": "2022-02-22",
|
||||
"_now:datetime": "2022-02-22 10:15:51",
|
||||
"_loaded:date": "2022-02-22",
|
||||
"_loaded:datetime": "2022-02-22 10:15:51",
|
||||
"_geometry:type": "Polygon",
|
||||
"_intersects_with_other_features": "",
|
||||
"_country": "be",
|
||||
"_overlaps_with_buildings": "[]",
|
||||
"_overlap_percentage": "null",
|
||||
"_grb_date": "2014-04-28",
|
||||
"_grb_ref": "Gbg/150044",
|
||||
"_building:min_level": "",
|
||||
"_surface": "548.1242491529038",
|
||||
"_surface:ha": "0",
|
||||
"_reverse_overlap_percentage": "null",
|
||||
"_imported_osm_object_found": "false",
|
||||
"_imported_osm_still_fresh": "false",
|
||||
"_target_building_type": "house"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": <[number, number][][]>[
|
||||
[
|
||||
[
|
||||
5.262684300000043,
|
||||
50.84624409999995
|
||||
],
|
||||
[
|
||||
5.262777500000024,
|
||||
50.84620759999988
|
||||
],
|
||||
[
|
||||
5.262798899999998,
|
||||
50.84621390000019
|
||||
],
|
||||
[
|
||||
5.262999799999994,
|
||||
50.84619519999999
|
||||
],
|
||||
[
|
||||
5.263107500000007,
|
||||
50.84618920000014
|
||||
],
|
||||
[
|
||||
5.263115,
|
||||
50.84620990000026
|
||||
],
|
||||
[
|
||||
5.26310279999998,
|
||||
50.84623050000014
|
||||
],
|
||||
[
|
||||
5.263117999999977,
|
||||
50.846247400000166
|
||||
],
|
||||
[
|
||||
5.263174599999989,
|
||||
50.84631019999971
|
||||
],
|
||||
[
|
||||
5.263166999999989,
|
||||
50.84631459999995
|
||||
],
|
||||
[
|
||||
5.263243999999979,
|
||||
50.84640239999989
|
||||
],
|
||||
[
|
||||
5.2631607000000065,
|
||||
50.84643459999996
|
||||
],
|
||||
[
|
||||
5.26313309999997,
|
||||
50.84640089999985
|
||||
],
|
||||
[
|
||||
5.262907499999996,
|
||||
50.84647790000018
|
||||
],
|
||||
[
|
||||
5.2628939999999576,
|
||||
50.846463699999774
|
||||
],
|
||||
[
|
||||
5.262872100000033,
|
||||
50.846440700000294
|
||||
],
|
||||
[
|
||||
5.262784699999991,
|
||||
50.846348899999924
|
||||
],
|
||||
[
|
||||
5.262684300000043,
|
||||
50.84624409999995
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
5.262801899999976,
|
||||
50.84623269999982
|
||||
],
|
||||
[
|
||||
5.2629535000000285,
|
||||
50.84638830000012
|
||||
],
|
||||
[
|
||||
5.263070700000018,
|
||||
50.84634720000008
|
||||
],
|
||||
[
|
||||
5.262998000000025,
|
||||
50.84626279999982
|
||||
],
|
||||
[
|
||||
5.263066799999966,
|
||||
50.84623959999975
|
||||
],
|
||||
[
|
||||
5.263064000000004,
|
||||
50.84623330000007
|
||||
],
|
||||
[
|
||||
5.263009599999997,
|
||||
50.84623730000026
|
||||
],
|
||||
[
|
||||
5.263010199999956,
|
||||
50.84621629999986
|
||||
],
|
||||
[
|
||||
5.262801899999976,
|
||||
50.84623269999982
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
const innerRings = [...feature.geometry.coordinates]
|
||||
innerRings.splice(0, 1)
|
||||
|
||||
const action = new CreateMultiPolygonWithPointReuseAction(
|
||||
[new Tag("building", "yes")],
|
||||
feature.geometry.coordinates[0],
|
||||
innerRings,
|
||||
undefined,
|
||||
[],
|
||||
"import"
|
||||
)
|
||||
const descriptions = await action.Perform(new Changes())
|
||||
|
||||
function getCoor(id: number): {lat: number, lon:number} {
|
||||
return <any> descriptions.find(d => d.type === "node" && d.id === id).changes
|
||||
}
|
||||
|
||||
const ways= descriptions.filter(d => d.type === "way")
|
||||
T.isTrue(ways[0].id == -18, "unexpected id")
|
||||
T.isTrue(ways[1].id == -27, "unexpected id")
|
||||
const outer = ways[0].changes["coordinates"]
|
||||
const outerExpected = [[5.262684300000043,50.84624409999995],[5.262777500000024,50.84620759999988],[5.262798899999998,50.84621390000019],[5.262999799999994,50.84619519999999],[5.263107500000007,50.84618920000014],[5.263115,50.84620990000026],[5.26310279999998,50.84623050000014],[5.263117999999977,50.846247400000166],[5.263174599999989,50.84631019999971],[5.263166999999989,50.84631459999995],[5.263243999999979,50.84640239999989],[5.2631607000000065,50.84643459999996],[5.26313309999997,50.84640089999985],[5.262907499999996,50.84647790000018],[5.2628939999999576,50.846463699999774],[5.262872100000033,50.846440700000294],[5.262784699999991,50.846348899999924],[5.262684300000043,50.84624409999995]]
|
||||
T.listIdentical(feature.geometry.coordinates[0], outer)
|
||||
const inner = ways[1].changes["coordinates"]
|
||||
T.listIdentical(feature.geometry.coordinates[1], inner)
|
||||
const members = <{type: string, role: string, ref: number}[]> descriptions.find(d => d.type === "relation").changes["members"]
|
||||
T.isTrue(members[0].role == "outer", "incorrect role")
|
||||
T.isTrue(members[1].role == "inner", "incorrect role")
|
||||
T.isTrue(members[0].type == "way", "incorrect type")
|
||||
T.isTrue(members[1].type == "way", "incorrect type")
|
||||
T.isTrue(members[0].ref == -18, "incorrect id")
|
||||
T.isTrue(members[1].ref == -27, "incorrect id")
|
||||
}]
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,659 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import {FixLegacyTheme} from "../Models/ThemeConfig/Conversion/LegacyJsonConvert";
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
|
||||
import {TagRenderingConfigJson} from "../Models/ThemeConfig/Json/TagRenderingConfigJson";
|
||||
import {AddMiniMap} from "../Models/ThemeConfig/Conversion/PrepareTheme";
|
||||
import {DetectMappingsWithImages, DetectShadowedMappings} from "../Models/ThemeConfig/Conversion/Validation";
|
||||
import * as Assert from "assert";
|
||||
import {ExtractImages, FixImages} from "../Models/ThemeConfig/Conversion/FixImages";
|
||||
import {PrepareLayer} from "../Models/ThemeConfig/Conversion/PrepareLayer";
|
||||
import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson";
|
||||
import LineRenderingConfigJson from "../Models/ThemeConfig/Json/LineRenderingConfigJson";
|
||||
|
||||
export default class LegacyThemeLoaderSpec extends T {
|
||||
|
||||
private static readonly walking_node_theme = {
|
||||
"id": "walkingnodenetworks",
|
||||
"title": {
|
||||
"en": "Walking node networks"
|
||||
},
|
||||
"maintainer": "L'imaginaire",
|
||||
"icon": "https://upload.wikimedia.org/wikipedia/commons/3/30/Man_walking_icon_1410105361.svg",
|
||||
"description": {
|
||||
"en": "This map shows walking node networks"
|
||||
},
|
||||
"language": [
|
||||
"en"
|
||||
],
|
||||
socialImage: "img.jpg",
|
||||
"version": "2021-10-02",
|
||||
"startLat": 51.1599,
|
||||
"startLon": 3.34750,
|
||||
"startZoom": 12,
|
||||
"clustering": {
|
||||
"maxZoom": 12
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"id": "node2node",
|
||||
"name": {
|
||||
"en": "node to node links"
|
||||
},
|
||||
"source": {
|
||||
"osmTags": {
|
||||
"and": [
|
||||
"network=rwn",
|
||||
"network:type=node_network"
|
||||
]
|
||||
}
|
||||
},
|
||||
"minzoom": 12,
|
||||
"title": {
|
||||
"render": {
|
||||
"en": "node to node link"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "ref~*",
|
||||
"then": {
|
||||
"en": "node to node link <strong>{ref}</strong>"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"width": {
|
||||
"render": "4"
|
||||
},
|
||||
"color": {
|
||||
"render": "#8b1e20"
|
||||
},
|
||||
"tagRenderings": [
|
||||
{
|
||||
"question": {
|
||||
"en": "When was this node to node link last surveyed?"
|
||||
},
|
||||
"render": {
|
||||
"en": "This node to node link was last surveyed on {survey:date}"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "survey:date",
|
||||
"type": "date"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "survey:date:={_now:date}",
|
||||
"then": "Surveyed today!"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "node",
|
||||
"name": {
|
||||
"en": "nodes"
|
||||
},
|
||||
"source": {
|
||||
"osmTags": "rwn_ref~*"
|
||||
},
|
||||
"minzoom": 12,
|
||||
"title": {
|
||||
"render": {
|
||||
"en": "walking node <strong>{rwn_ref}</strong>"
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"mappings": [
|
||||
{
|
||||
"if": "rwn_ref~*",
|
||||
"then": "<div style='position: absolute; top: 10px; right: 10px; color: white; background-color: #8b1e20; width: 20px; height: 20px; border-radius: 100%'>{rwn_ref}</div>"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tagRenderings": [
|
||||
{
|
||||
"question": {
|
||||
"en": "When was this walking node last surveyed?"
|
||||
},
|
||||
"render": {
|
||||
"en": "This walking node was last surveyed on {survey:date}"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "survey:date",
|
||||
"type": "date"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "survey:date:={_now:date}",
|
||||
"then": "Surveyed today!"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": {
|
||||
"en": "How many other walking nodes does this node link to?"
|
||||
},
|
||||
"render": {
|
||||
"en": "This node links to {expected_rwn_route_relations} other walking nodes."
|
||||
},
|
||||
"freeform": {
|
||||
"key": "expected_rwn_route_relations",
|
||||
"type": "int"
|
||||
}
|
||||
},
|
||||
"images"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
private static readonly verkeerde_borden = {
|
||||
"id": "https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/VerkeerdeBordenDatabank.json",
|
||||
"title": {
|
||||
"nl": "VerkeerdeBordenDatabank",
|
||||
"en": "Erratic Signs Database"
|
||||
},
|
||||
"maintainer": "Seppe Santens",
|
||||
"icon": "https://upload.wikimedia.org/wikipedia/commons/b/bc/Belgian_traffic_sign_A51.svg",
|
||||
"description": {
|
||||
"nl": "Een kaart om verkeerde of ontbrekende verkeersborden te tonen en te editeren.",
|
||||
"en": "A map to show and edit incorrect or missing traffic signs."
|
||||
},
|
||||
"version": "2021-09-16",
|
||||
"startLat": 51.08881,
|
||||
"startLon": 3.447282,
|
||||
"startZoom": 15,
|
||||
"clustering": {
|
||||
"maxZoom": 8
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"id": "trafficsign",
|
||||
"name": {
|
||||
"nl": "verkeersbord",
|
||||
"en": "traffic sign"
|
||||
},
|
||||
"source": {
|
||||
"osmTags": {
|
||||
"and": [
|
||||
"traffic_sign~*",
|
||||
"traffic_sign:issue~*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"minzoom": 10,
|
||||
"title": {
|
||||
"render": {
|
||||
"nl": "verkeersbord",
|
||||
"en": "traffic sign"
|
||||
}
|
||||
},
|
||||
"tagRenderings": [
|
||||
"images",
|
||||
{
|
||||
"render": {
|
||||
"nl": "ID verkeersbord: {traffic_sign}",
|
||||
"en": "traffic sign ID: {traffic_sign}"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat is het ID voor dit verkeersbord?",
|
||||
"en": "What is ID for this traffic sign?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "traffic_sign"
|
||||
},
|
||||
"id": "trafficsign-traffic_sign"
|
||||
},
|
||||
{
|
||||
"render": {
|
||||
"nl": "Probleem bij dit verkeersbord: {traffic_sign:issue}",
|
||||
"en": "Issue with this traffic sign: {traffic_sign:issue}"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat is het probleem met dit verkeersbord?",
|
||||
"en": "What is the issue with this traffic sign?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "traffic_sign:issue"
|
||||
},
|
||||
"id": "trafficsign-traffic_sign:issue"
|
||||
},
|
||||
{
|
||||
"question": {
|
||||
"nl": "Wanneer werd dit verkeersbord laatst gesurveyed?",
|
||||
"en": "When was this traffic sign last surveyed?"
|
||||
},
|
||||
"render": {
|
||||
"nl": "Dit verkeersbord werd laatst gesurveyed op {survey:date}",
|
||||
"en": "This traffic sign was last surveyed on {survey:date}"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "survey:date",
|
||||
"type": "date"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "survey:date:={_now:date}",
|
||||
"then": "Vandaag gesurveyed!"
|
||||
}
|
||||
],
|
||||
"id": "trafficsign-survey:date"
|
||||
}
|
||||
],
|
||||
"mapRendering": [
|
||||
{
|
||||
"icon": "./TS_bolt.svg",
|
||||
iconBadges: [{
|
||||
if: "id=yes",
|
||||
then: {
|
||||
mappings: [
|
||||
{
|
||||
if: "id=yes",
|
||||
then: "./Something.svg"
|
||||
}
|
||||
]
|
||||
}
|
||||
}],
|
||||
"location": [
|
||||
"point",
|
||||
"centroid"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "notrafficsign",
|
||||
"name": {
|
||||
"nl": "geen verkeersbord",
|
||||
"en": "no traffic sign"
|
||||
},
|
||||
"source": {
|
||||
"osmTags": {
|
||||
"and": [
|
||||
{
|
||||
"or": [
|
||||
"no:traffic_sign~*",
|
||||
"not:traffic_sign~*"
|
||||
]
|
||||
},
|
||||
"traffic_sign:issue~*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"minzoom": 10,
|
||||
"title": {
|
||||
"render": {
|
||||
"nl": "ontbrekend verkeersbord",
|
||||
"en": "missing traffic sign"
|
||||
}
|
||||
},
|
||||
"tagRenderings": [
|
||||
"images",
|
||||
{
|
||||
"render": {
|
||||
"nl": "ID ontbrekend verkeersbord: {no:traffic_sign}",
|
||||
"en": "missing traffic sign ID: {no:traffic_sign}"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat is het ID voor het ontbrekende verkeersbord?",
|
||||
"en": "What is ID for the missing traffic sign?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "no:traffic_sign"
|
||||
},
|
||||
"id": "notrafficsign-no:traffic_sign"
|
||||
},
|
||||
{
|
||||
"render": {
|
||||
"nl": "Probleem bij deze situatie: {traffic_sign:issue}",
|
||||
"en": "Issue with this situation: {traffic_sign:issue}"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat is er mis met deze situatie?",
|
||||
"en": "What is the issue with this situation?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "traffic_sign:issue"
|
||||
},
|
||||
"id": "notrafficsign-traffic_sign:issue"
|
||||
},
|
||||
{
|
||||
"question": {
|
||||
"nl": "Wanneer werd deze situatie laatst gesurveyed?",
|
||||
"en": "When was this situation last surveyed?"
|
||||
},
|
||||
"render": {
|
||||
"nl": "Deze situatie werd laatst gesurveyed op {survey:date}",
|
||||
"en": "This situation was last surveyed on {survey:date}"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "survey:date",
|
||||
"type": "date"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "survey:date:={_now:date}",
|
||||
"then": "Vandaag gesurveyed!"
|
||||
}
|
||||
],
|
||||
"id": "notrafficsign-survey:date"
|
||||
}
|
||||
],
|
||||
"mapRendering": [
|
||||
{
|
||||
"icon": "./TS_questionmark.svg",
|
||||
"location": [
|
||||
"point",
|
||||
"centroid"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"defaultBackgroundId": "Stamen.TonerLite"
|
||||
}
|
||||
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
["Walking_node_theme", () => {
|
||||
|
||||
const config = LegacyThemeLoaderSpec.walking_node_theme
|
||||
const fixed = new FixLegacyTheme().convert(
|
||||
// @ts-ignore
|
||||
config,
|
||||
"While testing")
|
||||
T.isTrue(fixed.errors.length === 0, "Could not fix the legacy theme")
|
||||
const theme = new LayoutConfig(fixed.result)
|
||||
|
||||
}],
|
||||
["Detect minimaps", () => {
|
||||
function shouldHave(config: TagRenderingConfigJson) {
|
||||
T.equals(AddMiniMap.hasMinimap(config), true, "Did _not_ dected a minimap, even though there is one in " + JSON.stringify(config))
|
||||
}
|
||||
|
||||
function shouldNot(config: TagRenderingConfigJson) {
|
||||
T.equals(AddMiniMap.hasMinimap(config), false, "Did erronously dected a minimap, even though there is none in " + JSON.stringify(config))
|
||||
}
|
||||
|
||||
shouldHave({
|
||||
render: "{minimap()}"
|
||||
});
|
||||
shouldHave({
|
||||
render: {en: "{minimap()}"}
|
||||
});
|
||||
shouldHave({
|
||||
render: {en: "{minimap()}", nl: "{minimap()}"}
|
||||
});
|
||||
shouldHave({
|
||||
render: {en: "{minimap()}", nl: "No map for the dutch!"}
|
||||
});
|
||||
|
||||
shouldHave({
|
||||
render: "{minimap()}"
|
||||
})
|
||||
shouldHave({
|
||||
render: "{minimap(18,featurelist)}"
|
||||
})
|
||||
shouldHave({
|
||||
mappings: [
|
||||
{
|
||||
if: "xyz=abc",
|
||||
then: "{minimap(18,featurelist)}"
|
||||
}
|
||||
]
|
||||
})
|
||||
shouldNot({
|
||||
render: "Some random value {key}"
|
||||
})
|
||||
shouldNot({
|
||||
render: "Some random value {minimap}"
|
||||
})
|
||||
|
||||
}],
|
||||
["Shadowed mappings are detected",
|
||||
() => {
|
||||
const r = new DetectShadowedMappings().convert({
|
||||
mappings: [
|
||||
{
|
||||
if: {or: ["key=value", "x=y"]},
|
||||
then: "Case A"
|
||||
},
|
||||
{
|
||||
if: "key=value",
|
||||
then: "Shadowed"
|
||||
}
|
||||
]
|
||||
}, "test");
|
||||
T.isTrue(r.warnings.length > 0, "Failing case 0 is not detected")
|
||||
T.isTrue(r.warnings[0].indexOf("The mapping key=value is fully matched by a previous mapping (namely 0)") >= 0, "Error message does not contain tag and indices")
|
||||
const r0 = new DetectShadowedMappings().convert({
|
||||
mappings: [
|
||||
{
|
||||
if: {or: ["key=value", "x=y"]},
|
||||
then: "Case A"
|
||||
},
|
||||
{
|
||||
if: {and: ["key=value", "x=y"]},
|
||||
then: "Shadowed"
|
||||
}
|
||||
]
|
||||
}, "test");
|
||||
T.isTrue(r0.warnings.length > 0, "Failing case 1 is not detected")
|
||||
}
|
||||
],
|
||||
["Images are rewritten", () => {
|
||||
const fixed = new FixImages(new Set<string>()).convertStrict(LegacyThemeLoaderSpec.verkeerde_borden, "test")
|
||||
const fixedValue = fixed.layers[0]["mapRendering"][0].icon
|
||||
Assert.equal("https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/TS_bolt.svg",
|
||||
fixedValue)
|
||||
|
||||
const fixedMapping = fixed.layers[0]["mapRendering"][0].iconBadges[0].then.mappings[0].then
|
||||
Assert.equal("https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/Something.svg",
|
||||
fixedMapping)
|
||||
}],
|
||||
["Images in simple mappings are detected", () => {
|
||||
const r = new DetectMappingsWithImages().convert({
|
||||
"mappings": [
|
||||
{
|
||||
"if": "bicycle_parking=stands",
|
||||
"then": {
|
||||
"en": "Staple racks <img style='width: 25%' src='./assets/layers/bike_parking/staple.svg'>",
|
||||
"nl": "Nietjes <img style='width: 25%'' src='./assets/layers/bike_parking/staple.svg'>",
|
||||
"fr": "Arceaux <img style='width: 25%'' src='./assets/layers/bike_parking/staple.svg'>",
|
||||
"gl": "De roda (Stands) <img style='width: 25%'' src='./assets/layers/bike_parking/staple.svg'>",
|
||||
"de": "Fahrradbügel <img style='width: 25%'' src='./assets/layers/bike_parking/staple.svg'>",
|
||||
"hu": "Korlát <img style='width: 25%' src='./assets/layers/bike_parking/staple.svg'>",
|
||||
"it": "Archetti <img style='width: 25%' src='./assets/layers/bike_parking/staple.svg'>",
|
||||
"zh_Hant": "單車架 <img style='width: 25%' src='./assets/layers/bike_parking/staple.svg'>"
|
||||
}
|
||||
}]
|
||||
}, "test");
|
||||
const errors = r.errors;
|
||||
T.isTrue(errors.length > 0, "No images found");
|
||||
T.isTrue(errors.some(msg => msg.indexOf("./assets/layers/bike_parking/staple.svg") >= 0), "staple.svg not mentioned");
|
||||
}],
|
||||
["Images in 'thens' are detected in QuestionableTagRenderings", () => {
|
||||
const r = new ExtractImages(true, new Map<string, any>()).convert(<any>{
|
||||
"layers": [
|
||||
{
|
||||
tagRenderings: [
|
||||
{
|
||||
"mappings": [
|
||||
{
|
||||
"if": "bicycle_parking=stands",
|
||||
"then": {
|
||||
"en": "Staple racks",
|
||||
},
|
||||
"icon": {
|
||||
path: "./assets/layers/bike_parking/staple.svg",
|
||||
class: "small"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "bicycle_parking=stands",
|
||||
"then": {
|
||||
"en": "Bollard",
|
||||
},
|
||||
"icon": "./assets/layers/bike_parking/bollard.svg",
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}, "test");
|
||||
const images = r.result
|
||||
T.isTrue(images.length > 0, "No images found");
|
||||
T.isTrue(images.findIndex(img => img == "./assets/layers/bike_parking/staple.svg") >= 0, "staple.svg not mentioned");
|
||||
T.isTrue(images.findIndex(img => img == "./assets/layers/bike_parking/bollard.svg") >= 0, "bollard.svg not mentioned");
|
||||
}],
|
||||
["Rotation and colours is not detected as image", () => {
|
||||
const r = new ExtractImages(true, new Map<string, any>()).convert(<any>{
|
||||
"layers": [
|
||||
{
|
||||
mapRendering: [
|
||||
{
|
||||
"location": ["point", "centroid"],
|
||||
"icon": "pin:black",
|
||||
rotation: 180,
|
||||
iconSize: "40,40,center"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}, "test");
|
||||
const images = r.result
|
||||
T.isTrue(images.length > 0, "No images found");
|
||||
T.isTrue(images.length < 2, "To much images found: " + images.join(", "));
|
||||
T.isTrue(images[0] === "pin", "pin not mentioned");
|
||||
}],
|
||||
["Test expansion in map renderings", () => {
|
||||
const exampleLayer: LayerConfigJson = {
|
||||
id: "testlayer",
|
||||
source: {
|
||||
osmTags: "key=value"
|
||||
},
|
||||
mapRendering: [
|
||||
{
|
||||
"rewrite": {
|
||||
sourceString: ["left|right", "lr_offset"],
|
||||
into: [
|
||||
["left", "right"],
|
||||
[-6, +6]
|
||||
]
|
||||
},
|
||||
renderings: <LineRenderingConfigJson>{
|
||||
"color": {
|
||||
"render": "#888",
|
||||
"mappings": [
|
||||
{
|
||||
"if": "parking:condition:left|right=free",
|
||||
"then": "#299921"
|
||||
},
|
||||
{
|
||||
"if": "parking:condition:left|right=disc",
|
||||
"then": "#219991"
|
||||
}
|
||||
]
|
||||
},
|
||||
"offset": "lr_offset"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
const prep = new PrepareLayer({
|
||||
tagRenderings: new Map<string, TagRenderingConfigJson>(),
|
||||
sharedLayers: new Map<string, LayerConfigJson>()
|
||||
})
|
||||
const result = prep.convertStrict(exampleLayer, "test")
|
||||
|
||||
const expected = {
|
||||
"id": "testlayer",
|
||||
"source": {"osmTags": "key=value"},
|
||||
"mapRendering": [{
|
||||
"color": {
|
||||
"render": "#888",
|
||||
"mappings": [{
|
||||
"if": "parking:condition:left=free",
|
||||
"then": "#299921"
|
||||
},
|
||||
{"if": "parking:condition:left=disc",
|
||||
"then": "#219991"}]
|
||||
},
|
||||
"offset": -6
|
||||
}, {
|
||||
"color": {
|
||||
"render": "#888",
|
||||
"mappings": [{
|
||||
"if": "parking:condition:right=free",
|
||||
"then": "#299921"
|
||||
},
|
||||
{"if": "parking:condition:right=disc",
|
||||
"then": "#219991"}]
|
||||
},
|
||||
"offset": 6
|
||||
}],
|
||||
"titleIcons": [{"render": "defaults", "id": "defaults"}]
|
||||
}
|
||||
|
||||
|
||||
Assert.equal(JSON.stringify(result), JSON.stringify(expected))
|
||||
}
|
||||
|
||||
],
|
||||
["Advanced rewriting of the mapRendering",() => {
|
||||
const source = {"mapRendering": [
|
||||
{
|
||||
"rewrite": {
|
||||
"sourceString": ["left|right", "lr_offset"],
|
||||
"into": [
|
||||
["left", "right"],
|
||||
[-6, 6]
|
||||
]
|
||||
},
|
||||
"renderings": [
|
||||
{
|
||||
"color": {
|
||||
"render": "#888",
|
||||
"mappings": [
|
||||
{
|
||||
"if": "parking:condition:left|right=free",
|
||||
"then": "#299921"
|
||||
},
|
||||
{
|
||||
"if": "parking:condition:left|right=ticket",
|
||||
"then": "#219991"
|
||||
}
|
||||
]
|
||||
},
|
||||
"width": {
|
||||
"render": 6,
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"or": [
|
||||
"parking:lane:left|right=no",
|
||||
"parking:lane:left|right=separate"
|
||||
]
|
||||
},
|
||||
"then": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"offset": "lr_offset",
|
||||
"lineCap": "butt"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}}
|
||||
|
||||
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import UserDetails, {OsmConnection} from "../Logic/Osm/OsmConnection";
|
||||
import {UIEventSource} from "../Logic/UIEventSource";
|
||||
import ScriptUtils from "../scripts/ScriptUtils";
|
||||
|
||||
|
||||
export default class OsmConnectionSpec extends T {
|
||||
|
||||
/*
|
||||
This token gives access to the TESTING-instance of OSM. No real harm can be done with it, so it can be commited to the repo
|
||||
*/
|
||||
private static _osm_token = "LJFmv2nUicSNmBNsFeyCHx5KKx6Aiesx8pXPbX4n"
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
["login on dev",
|
||||
() => {
|
||||
const osmConn = new OsmConnection({
|
||||
osmConfiguration: "osm-test",
|
||||
oauth_token: new UIEventSource<string>(OsmConnectionSpec._osm_token)
|
||||
}
|
||||
);
|
||||
|
||||
osmConn.userDetails.map((userdetails: UserDetails) => {
|
||||
if (userdetails.loggedIn) {
|
||||
console.log("Logged in with the testing account. Writing some random data to test preferences")
|
||||
const data = Math.random().toString()
|
||||
osmConn.GetPreference("test").setData(data)
|
||||
|
||||
osmConn.GetPreference("https://raw.githubusercontent.com/AgusQui/MapCompleteRailway/main/railway")
|
||||
.setData(data)
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
ScriptUtils.sleep(1000)
|
||||
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import {OsmObject} from "../Logic/Osm/OsmObject";
|
||||
|
||||
export default class OsmObjectSpec extends T {
|
||||
constructor() {
|
||||
super([
|
||||
[
|
||||
"Download referencing ways",
|
||||
() => {
|
||||
OsmObjectSpec.runTest().then(_ => console.log("Referencing ways test is done (async)"))
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
|
||||
]);
|
||||
}
|
||||
|
||||
private static async runTest() {
|
||||
const ways = await OsmObject.DownloadReferencingWays("node/1124134958")
|
||||
if (ways === undefined) {
|
||||
throw "Did not get the ways"
|
||||
}
|
||||
if (ways.length !== 4) {
|
||||
throw "Expected 4 ways but got " + ways.length
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,690 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import {InPlaceReplacedmentRTSH, TurnRestrictionRSH} from "../Logic/Osm/Actions/RelationSplitHandler";
|
||||
import {OsmObject, OsmRelation} from "../Logic/Osm/OsmObject";
|
||||
import {Changes} from "../Logic/Osm/Changes";
|
||||
import {Utils} from "../Utils";
|
||||
|
||||
export default class RelationSplitHandlerSpec extends T {
|
||||
constructor() {
|
||||
|
||||
Utils.injectJsonDownloadForTests(
|
||||
"https://www.openstreetmap.org/api/0.6/node/1124134958/ways",
|
||||
{
|
||||
"version": "0.6",
|
||||
"generator": "CGImap 0.8.5 (2937646 spike-07.openstreetmap.org)",
|
||||
"copyright": "OpenStreetMap and contributors",
|
||||
"attribution": "http://www.openstreetmap.org/copyright",
|
||||
"license": "http://opendatacommons.org/licenses/odbl/1-0/",
|
||||
"elements": [{
|
||||
"type": "way",
|
||||
"id": 97038428,
|
||||
"timestamp": "2019-06-19T12:26:24Z",
|
||||
"version": 6,
|
||||
"changeset": 71399984,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858,
|
||||
"nodes": [1124134958, 323729212, 323729351, 2542460408, 187073405],
|
||||
"tags": {
|
||||
"highway": "residential",
|
||||
"name": "Brugs-Kerkhofstraat",
|
||||
"sett:pattern": "arc",
|
||||
"surface": "sett"
|
||||
}
|
||||
}, {
|
||||
"type": "way",
|
||||
"id": 97038434,
|
||||
"timestamp": "2019-06-19T12:26:24Z",
|
||||
"version": 5,
|
||||
"changeset": 71399984,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858,
|
||||
"nodes": [1124134958, 1124135024, 187058607],
|
||||
"tags": {
|
||||
"bicycle": "use_sidepath",
|
||||
"highway": "residential",
|
||||
"name": "Kerkhofblommenstraat",
|
||||
"sett:pattern": "arc",
|
||||
"surface": "sett"
|
||||
}
|
||||
}, {
|
||||
"type": "way",
|
||||
"id": 97038435,
|
||||
"timestamp": "2017-12-21T21:41:08Z",
|
||||
"version": 4,
|
||||
"changeset": 54826837,
|
||||
"user": "Jakka",
|
||||
"uid": 2403313,
|
||||
"nodes": [1124134958, 2576628889, 1124135035, 5298371485, 5298371495],
|
||||
"tags": {"bicycle": "use_sidepath", "highway": "residential", "name": "Kerkhofblommenstraat"}
|
||||
}, {
|
||||
"type": "way",
|
||||
"id": 251446313,
|
||||
"timestamp": "2019-01-07T19:22:47Z",
|
||||
"version": 4,
|
||||
"changeset": 66106872,
|
||||
"user": "M!dgard",
|
||||
"uid": 763799,
|
||||
"nodes": [1124134958, 5243143198, 4555715455],
|
||||
"tags": {"foot": "yes", "highway": "service"}
|
||||
}]
|
||||
}
|
||||
)
|
||||
|
||||
Utils.injectJsonDownloadForTests(
|
||||
"https://www.openstreetmap.org/api/0.6/relation/9572808",
|
||||
{
|
||||
"version": "0.6",
|
||||
"generator": "CGImap 0.8.5 (3128319 spike-07.openstreetmap.org)",
|
||||
"copyright": "OpenStreetMap and contributors",
|
||||
"attribution": "http://www.openstreetmap.org/copyright",
|
||||
"license": "http://opendatacommons.org/licenses/odbl/1-0/",
|
||||
"elements": [{
|
||||
"type": "relation",
|
||||
"id": 9572808,
|
||||
"timestamp": "2021-08-12T12:44:06Z",
|
||||
"version": 11,
|
||||
"changeset": 109573204,
|
||||
"user": "A67-A67",
|
||||
"uid": 553736,
|
||||
"members": [{"type": "way", "ref": 173662702, "role": ""}, {
|
||||
"type": "way",
|
||||
"ref": 467606230,
|
||||
"role": ""
|
||||
}, {"type": "way", "ref": 126267167, "role": ""}, {
|
||||
"type": "way",
|
||||
"ref": 301897426,
|
||||
"role": ""
|
||||
}, {"type": "way", "ref": 687866206, "role": ""}, {
|
||||
"type": "way",
|
||||
"ref": 295132739,
|
||||
"role": ""
|
||||
}, {"type": "way", "ref": 690497698, "role": ""}, {
|
||||
"type": "way",
|
||||
"ref": 627893684,
|
||||
"role": ""
|
||||
}, {"type": "way", "ref": 295132741, "role": ""}, {
|
||||
"type": "way",
|
||||
"ref": 301903120,
|
||||
"role": ""
|
||||
}, {"type": "way", "ref": 672541156, "role": ""}, {
|
||||
"type": "way",
|
||||
"ref": 126264330,
|
||||
"role": ""
|
||||
}, {"type": "way", "ref": 280440853, "role": ""}, {
|
||||
"type": "way",
|
||||
"ref": 838499667,
|
||||
"role": ""
|
||||
}, {"type": "way", "ref": 838499663, "role": ""}, {
|
||||
"type": "way",
|
||||
"ref": 690497623,
|
||||
"role": ""
|
||||
}, {"type": "way", "ref": 301902946, "role": ""}, {
|
||||
"type": "way",
|
||||
"ref": 280460715,
|
||||
"role": ""
|
||||
}, {"type": "way", "ref": 972534369, "role": ""}, {
|
||||
"type": "way",
|
||||
"ref": 695680702,
|
||||
"role": ""
|
||||
}, {"type": "way", "ref": 690497860, "role": ""}, {
|
||||
"type": "way",
|
||||
"ref": 295410363,
|
||||
"role": ""
|
||||
}, {"type": "way", "ref": 823864063, "role": ""}, {
|
||||
"type": "way",
|
||||
"ref": 663172088,
|
||||
"role": ""
|
||||
}, {"type": "way", "ref": 659950322, "role": ""}, {
|
||||
"type": "way",
|
||||
"ref": 659950323,
|
||||
"role": ""
|
||||
}, {"type": "way", "ref": 230180094, "role": ""}, {
|
||||
"type": "way",
|
||||
"ref": 690497912,
|
||||
"role": ""
|
||||
}, {"type": "way", "ref": 39588765, "role": ""}],
|
||||
"tags": {
|
||||
"distance": "13 km",
|
||||
"name": "Abdijenroute",
|
||||
"network": "lcn",
|
||||
"old_name": "Spoorlijn 58",
|
||||
"operator": "Toerisme West-Vlaanderen",
|
||||
"railway": "abandoned",
|
||||
"route": "bicycle",
|
||||
"type": "route",
|
||||
"wikipedia": "nl:Spoorlijn 58"
|
||||
}
|
||||
}]
|
||||
}
|
||||
)
|
||||
|
||||
Utils.injectJsonDownloadForTests(
|
||||
"https://www.openstreetmap.org/api/0.6/way/687866206/full",
|
||||
{
|
||||
"version": "0.6",
|
||||
"generator": "CGImap 0.8.5 (2601512 spike-07.openstreetmap.org)",
|
||||
"copyright": "OpenStreetMap and contributors",
|
||||
"attribution": "http://www.openstreetmap.org/copyright",
|
||||
"license": "http://opendatacommons.org/licenses/odbl/1-0/",
|
||||
"elements": [{
|
||||
"type": "node",
|
||||
"id": 5273988959,
|
||||
"lat": 51.1811406,
|
||||
"lon": 3.2427712,
|
||||
"timestamp": "2021-07-29T21:14:53Z",
|
||||
"version": 6,
|
||||
"changeset": 108847202,
|
||||
"user": "kaart_fietser",
|
||||
"uid": 11022240,
|
||||
"tags": {"network:type": "node_network", "rwn_ref": "32"}
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 6448669326,
|
||||
"lat": 51.1811346,
|
||||
"lon": 3.242891,
|
||||
"timestamp": "2019-05-04T22:44:12Z",
|
||||
"version": 1,
|
||||
"changeset": 69891295,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858,
|
||||
"tags": {"barrier": "bollard"}
|
||||
}, {
|
||||
"type": "way",
|
||||
"id": 687866206,
|
||||
"timestamp": "2019-05-06T20:52:20Z",
|
||||
"version": 2,
|
||||
"changeset": 69951497,
|
||||
"user": "noelbov",
|
||||
"uid": 8054928,
|
||||
"nodes": [6448669326, 5273988959],
|
||||
"tags": {
|
||||
"highway": "cycleway",
|
||||
"name": "Abdijenroute",
|
||||
"railway": "abandoned",
|
||||
"surface": "asphalt"
|
||||
}
|
||||
}]
|
||||
}
|
||||
)
|
||||
|
||||
Utils.injectJsonDownloadForTests(
|
||||
"https://www.openstreetmap.org/api/0.6/way/690497698/full",
|
||||
{
|
||||
"version": "0.6",
|
||||
"generator": "CGImap 0.8.5 (3023311 spike-07.openstreetmap.org)",
|
||||
"copyright": "OpenStreetMap and contributors",
|
||||
"attribution": "http://www.openstreetmap.org/copyright",
|
||||
"license": "http://opendatacommons.org/licenses/odbl/1-0/",
|
||||
"elements": [{
|
||||
"type": "node",
|
||||
"id": 170497152,
|
||||
"lat": 51.1832353,
|
||||
"lon": 3.2498759,
|
||||
"timestamp": "2018-04-24T00:29:37Z",
|
||||
"version": 7,
|
||||
"changeset": 58357376,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 2988218625,
|
||||
"lat": 51.1835053,
|
||||
"lon": 3.2503067,
|
||||
"timestamp": "2018-09-24T21:48:46Z",
|
||||
"version": 2,
|
||||
"changeset": 62895918,
|
||||
"user": "A67-A67",
|
||||
"uid": 553736
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 5273988967,
|
||||
"lat": 51.182659,
|
||||
"lon": 3.249004,
|
||||
"timestamp": "2017-12-09T18:40:21Z",
|
||||
"version": 1,
|
||||
"changeset": 54493533,
|
||||
"user": "CacherB",
|
||||
"uid": 1999108
|
||||
}, {
|
||||
"type": "way",
|
||||
"id": 690497698,
|
||||
"timestamp": "2021-07-29T21:14:53Z",
|
||||
"version": 3,
|
||||
"changeset": 108847202,
|
||||
"user": "kaart_fietser",
|
||||
"uid": 11022240,
|
||||
"nodes": [2988218625, 170497152, 5273988967],
|
||||
"tags": {
|
||||
"highway": "cycleway",
|
||||
"lit": "no",
|
||||
"name": "Abdijenroute",
|
||||
"oneway": "no",
|
||||
"railway": "abandoned",
|
||||
"surface": "compacted"
|
||||
}
|
||||
}]
|
||||
}
|
||||
)
|
||||
Utils.injectJsonDownloadForTests(
|
||||
"https://www.openstreetmap.org/api/0.6/relation/4374576",
|
||||
{
|
||||
"version": "0.6",
|
||||
"generator": "CGImap 0.8.5 (1266692 spike-06.openstreetmap.org)",
|
||||
"copyright": "OpenStreetMap and contributors",
|
||||
"attribution": "http://www.openstreetmap.org/copyright",
|
||||
"license": "http://opendatacommons.org/licenses/odbl/1-0/",
|
||||
"elements": [{
|
||||
"type": "relation",
|
||||
"id": 4374576,
|
||||
"timestamp": "2014-12-23T21:42:27Z",
|
||||
"version": 2,
|
||||
"changeset": 27660623,
|
||||
"user": "escada",
|
||||
"uid": 436365,
|
||||
"members": [{"type": "way", "ref": 318616190, "role": "from"}, {
|
||||
"type": "node",
|
||||
"ref": 1407529979,
|
||||
"role": "via"
|
||||
}, {"type": "way", "ref": 143298912, "role": "to"}],
|
||||
"tags": {"restriction": "no_right_turn", "type": "restriction"}
|
||||
}]
|
||||
}
|
||||
)
|
||||
|
||||
Utils.injectJsonDownloadForTests(
|
||||
"https://www.openstreetmap.org/api/0.6/way/143298912/full",
|
||||
{
|
||||
"version": "0.6",
|
||||
"generator": "CGImap 0.8.5 (4046166 spike-07.openstreetmap.org)",
|
||||
"copyright": "OpenStreetMap and contributors",
|
||||
"attribution": "http://www.openstreetmap.org/copyright",
|
||||
"license": "http://opendatacommons.org/licenses/odbl/1-0/",
|
||||
"elements": [{
|
||||
"type": "node",
|
||||
"id": 26343912,
|
||||
"lat": 51.2146847,
|
||||
"lon": 3.2397007,
|
||||
"timestamp": "2015-04-11T10:40:56Z",
|
||||
"version": 5,
|
||||
"changeset": 30139621,
|
||||
"user": "M!dgard",
|
||||
"uid": 763799
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 26343913,
|
||||
"lat": 51.2161912,
|
||||
"lon": 3.2386907,
|
||||
"timestamp": "2015-04-11T10:40:56Z",
|
||||
"version": 6,
|
||||
"changeset": 30139621,
|
||||
"user": "M!dgard",
|
||||
"uid": 763799
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 26343914,
|
||||
"lat": 51.2193456,
|
||||
"lon": 3.2360696,
|
||||
"timestamp": "2015-04-11T10:40:56Z",
|
||||
"version": 5,
|
||||
"changeset": 30139621,
|
||||
"user": "M!dgard",
|
||||
"uid": 763799
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 26343915,
|
||||
"lat": 51.2202816,
|
||||
"lon": 3.2352429,
|
||||
"timestamp": "2015-04-11T10:40:56Z",
|
||||
"version": 5,
|
||||
"changeset": 30139621,
|
||||
"user": "M!dgard",
|
||||
"uid": 763799
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 875668688,
|
||||
"lat": 51.2131868,
|
||||
"lon": 3.2406009,
|
||||
"timestamp": "2015-04-11T10:40:56Z",
|
||||
"version": 4,
|
||||
"changeset": 30139621,
|
||||
"user": "M!dgard",
|
||||
"uid": 763799
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1109632153,
|
||||
"lat": 51.2207068,
|
||||
"lon": 3.234882,
|
||||
"timestamp": "2015-04-11T10:40:55Z",
|
||||
"version": 3,
|
||||
"changeset": 30139621,
|
||||
"user": "M!dgard",
|
||||
"uid": 763799
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1109632154,
|
||||
"lat": 51.220784,
|
||||
"lon": 3.2348394,
|
||||
"timestamp": "2021-05-30T08:01:17Z",
|
||||
"version": 4,
|
||||
"changeset": 105557550,
|
||||
"user": "albertino",
|
||||
"uid": 499281
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1109632177,
|
||||
"lat": 51.2205082,
|
||||
"lon": 3.2350441,
|
||||
"timestamp": "2015-04-11T10:40:55Z",
|
||||
"version": 3,
|
||||
"changeset": 30139621,
|
||||
"user": "M!dgard",
|
||||
"uid": 763799
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1407529961,
|
||||
"lat": 51.2168476,
|
||||
"lon": 3.2381772,
|
||||
"timestamp": "2015-04-11T10:40:55Z",
|
||||
"version": 2,
|
||||
"changeset": 30139621,
|
||||
"user": "M!dgard",
|
||||
"uid": 763799
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1407529969,
|
||||
"lat": 51.2155155,
|
||||
"lon": 3.23917,
|
||||
"timestamp": "2011-08-21T20:08:27Z",
|
||||
"version": 1,
|
||||
"changeset": 9088257,
|
||||
"user": "toeklk",
|
||||
"uid": 219908
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1407529979,
|
||||
"lat": 51.212694,
|
||||
"lon": 3.2409595,
|
||||
"timestamp": "2015-04-11T10:40:55Z",
|
||||
"version": 6,
|
||||
"changeset": 30139621,
|
||||
"user": "M!dgard",
|
||||
"uid": 763799,
|
||||
"tags": {"highway": "traffic_signals"}
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1634435395,
|
||||
"lat": 51.2129189,
|
||||
"lon": 3.2408257,
|
||||
"timestamp": "2012-02-15T19:37:51Z",
|
||||
"version": 1,
|
||||
"changeset": 10695640,
|
||||
"user": "Eimai",
|
||||
"uid": 6072
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1634435396,
|
||||
"lat": 51.2132508,
|
||||
"lon": 3.2405417,
|
||||
"timestamp": "2012-02-15T19:37:51Z",
|
||||
"version": 1,
|
||||
"changeset": 10695640,
|
||||
"user": "Eimai",
|
||||
"uid": 6072
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1634435397,
|
||||
"lat": 51.2133918,
|
||||
"lon": 3.2404416,
|
||||
"timestamp": "2015-04-11T10:40:55Z",
|
||||
"version": 2,
|
||||
"changeset": 30139621,
|
||||
"user": "M!dgard",
|
||||
"uid": 763799
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1974988033,
|
||||
"lat": 51.2127459,
|
||||
"lon": 3.240928,
|
||||
"timestamp": "2012-10-20T12:24:13Z",
|
||||
"version": 1,
|
||||
"changeset": 13566903,
|
||||
"user": "skyman81",
|
||||
"uid": 955688
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 3250129361,
|
||||
"lat": 51.2127906,
|
||||
"lon": 3.2409016,
|
||||
"timestamp": "2018-12-19T00:00:33Z",
|
||||
"version": 2,
|
||||
"changeset": 65596519,
|
||||
"user": "beardhatcode",
|
||||
"uid": 5439560,
|
||||
"tags": {"crossing": "traffic_signals", "highway": "crossing"}
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 3250129363,
|
||||
"lat": 51.2149189,
|
||||
"lon": 3.2395571,
|
||||
"timestamp": "2015-04-11T10:40:56Z",
|
||||
"version": 2,
|
||||
"changeset": 30139621,
|
||||
"user": "M!dgard",
|
||||
"uid": 763799
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 3450326133,
|
||||
"lat": 51.2139571,
|
||||
"lon": 3.2401205,
|
||||
"timestamp": "2015-04-11T10:40:26Z",
|
||||
"version": 1,
|
||||
"changeset": 30139621,
|
||||
"user": "M!dgard",
|
||||
"uid": 763799
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 3450326135,
|
||||
"lat": 51.2181385,
|
||||
"lon": 3.2370893,
|
||||
"timestamp": "2015-04-11T10:40:26Z",
|
||||
"version": 1,
|
||||
"changeset": 30139621,
|
||||
"user": "M!dgard",
|
||||
"uid": 763799
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4794847239,
|
||||
"lat": 51.2191224,
|
||||
"lon": 3.2362584,
|
||||
"timestamp": "2019-08-27T23:07:05Z",
|
||||
"version": 2,
|
||||
"changeset": 73816461,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 8493044168,
|
||||
"lat": 51.2130348,
|
||||
"lon": 3.2407284,
|
||||
"timestamp": "2021-03-06T21:52:51Z",
|
||||
"version": 1,
|
||||
"changeset": 100555232,
|
||||
"user": "kaart_fietser",
|
||||
"uid": 11022240,
|
||||
"tags": {"highway": "traffic_signals", "traffic_signals": "traffic_lights"}
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 8792687918,
|
||||
"lat": 51.2207505,
|
||||
"lon": 3.2348579,
|
||||
"timestamp": "2021-06-02T18:27:15Z",
|
||||
"version": 1,
|
||||
"changeset": 105735092,
|
||||
"user": "albertino",
|
||||
"uid": 499281
|
||||
}, {
|
||||
"type": "way",
|
||||
"id": 143298912,
|
||||
"timestamp": "2021-06-02T18:27:15Z",
|
||||
"version": 15,
|
||||
"changeset": 105735092,
|
||||
"user": "albertino",
|
||||
"uid": 499281,
|
||||
"nodes": [1407529979, 1974988033, 3250129361, 1634435395, 8493044168, 875668688, 1634435396, 1634435397, 3450326133, 26343912, 3250129363, 1407529969, 26343913, 1407529961, 3450326135, 4794847239, 26343914, 26343915, 1109632177, 1109632153, 8792687918, 1109632154],
|
||||
"tags": {
|
||||
"cycleway:right": "track",
|
||||
"highway": "primary",
|
||||
"lanes": "2",
|
||||
"lit": "yes",
|
||||
"maxspeed": "70",
|
||||
"name": "Buiten Kruisvest",
|
||||
"oneway": "yes",
|
||||
"ref": "R30",
|
||||
"surface": "asphalt",
|
||||
"wikipedia": "nl:Buiten Kruisvest"
|
||||
}
|
||||
}]
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
super([
|
||||
["split 295132739",
|
||||
async () => {
|
||||
// Lets mimick a split action of https://www.openstreetmap.org/way/295132739
|
||||
|
||||
const relation: OsmRelation = <OsmRelation>await OsmObject.DownloadObjectAsync("relation/9572808")
|
||||
const originalNodeIds = [5273988967,
|
||||
170497153,
|
||||
1507524582,
|
||||
4524321710,
|
||||
170497155,
|
||||
170497157,
|
||||
170497158,
|
||||
3208166179,
|
||||
1507524610,
|
||||
170497160,
|
||||
3208166178,
|
||||
1507524573,
|
||||
1575932830,
|
||||
6448669326]
|
||||
|
||||
const withSplit = [[5273988967,
|
||||
170497153,
|
||||
1507524582,
|
||||
4524321710,
|
||||
170497155,
|
||||
170497157,
|
||||
170497158],
|
||||
[
|
||||
3208166179,
|
||||
1507524610,
|
||||
170497160,
|
||||
3208166178,
|
||||
1507524573,
|
||||
1575932830,
|
||||
6448669326]]
|
||||
|
||||
const splitter = new InPlaceReplacedmentRTSH(
|
||||
{
|
||||
relation: relation,
|
||||
originalWayId: 295132739,
|
||||
allWayIdsInOrder: [295132739, -1],
|
||||
originalNodes: originalNodeIds,
|
||||
allWaysNodesInOrder: withSplit
|
||||
}, "no-theme")
|
||||
const changeDescription = await splitter.CreateChangeDescriptions(new Changes())
|
||||
const allIds = changeDescription[0].changes["members"].map(m => m.ref).join(",")
|
||||
const expected = "687866206,295132739,-1,690497698"
|
||||
T.isTrue(allIds.indexOf(expected) >= 0, "didn't find the expected order of ids in the relation to test")
|
||||
}],
|
||||
["split https://www.openstreetmap.org/way/143298912 (turn restriction relation)",
|
||||
async () => {
|
||||
|
||||
|
||||
const relation: OsmRelation = <OsmRelation>await OsmObject.DownloadObjectAsync("relation/4374576")
|
||||
const originalNodeIds =
|
||||
[
|
||||
1407529979,
|
||||
1974988033,
|
||||
3250129361,
|
||||
1634435395,
|
||||
8493044168,
|
||||
875668688,
|
||||
1634435396,
|
||||
1634435397,
|
||||
3450326133,
|
||||
26343912,
|
||||
3250129363,
|
||||
1407529969,
|
||||
26343913,
|
||||
1407529961,
|
||||
3450326135,
|
||||
4794847239,
|
||||
26343914,
|
||||
26343915,
|
||||
1109632177,
|
||||
1109632153,
|
||||
8792687918,
|
||||
1109632154
|
||||
|
||||
]
|
||||
|
||||
const withSplit = [[
|
||||
1407529979, // The via point
|
||||
1974988033,
|
||||
3250129361,
|
||||
1634435395,
|
||||
8493044168,
|
||||
875668688,
|
||||
1634435396,
|
||||
1634435397,
|
||||
3450326133,
|
||||
26343912,
|
||||
3250129363,
|
||||
1407529969,
|
||||
26343913],
|
||||
[
|
||||
1407529961,
|
||||
3450326135,
|
||||
4794847239,
|
||||
26343914,
|
||||
26343915,
|
||||
1109632177,
|
||||
1109632153,
|
||||
8792687918,
|
||||
1109632154
|
||||
|
||||
]]
|
||||
|
||||
const splitter = new TurnRestrictionRSH(
|
||||
{
|
||||
relation: relation,
|
||||
originalWayId: 143298912,
|
||||
allWayIdsInOrder: [-1, 143298912],
|
||||
originalNodes: originalNodeIds,
|
||||
allWaysNodesInOrder: withSplit
|
||||
}, "no-theme")
|
||||
const changeDescription = await splitter.CreateChangeDescriptions(new Changes())
|
||||
const allIds = changeDescription[0].changes["members"].map(m => m.type + "/" + m.ref + "-->" + m.role).join(",")
|
||||
const expected = "way/318616190-->from,node/1407529979-->via,way/-1-->to"
|
||||
T.equals(expected, allIds)
|
||||
|
||||
|
||||
// Reversing the ids has no effect
|
||||
const splitterReverse = new TurnRestrictionRSH(
|
||||
{
|
||||
relation: relation,
|
||||
originalWayId: 143298912,
|
||||
allWayIdsInOrder: [143298912, -1],
|
||||
originalNodes: originalNodeIds,
|
||||
allWaysNodesInOrder: withSplit
|
||||
}, "no-theme")
|
||||
const changesReverse = await splitterReverse.CreateChangeDescriptions(new Changes())
|
||||
T.equals(0, changesReverse.length, "Reverse turn restriction split did generate a changedescription, should not be needed")
|
||||
|
||||
}
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,932 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import {Utils} from "../Utils";
|
||||
import ReplaceGeometryAction from "../Logic/Osm/Actions/ReplaceGeometryAction";
|
||||
import * as grb from "../assets/themes/grb_import/grb.json"
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
|
||||
import State from "../State";
|
||||
import {BBox} from "../Logic/BBox";
|
||||
import Minimap from "../UI/Base/Minimap";
|
||||
|
||||
export default class ReplaceGeometrySpec extends T {
|
||||
|
||||
private static readonly grbStripped = {
|
||||
"id": "grb",
|
||||
"title": {
|
||||
"nl": "GRB import helper"
|
||||
},
|
||||
"description": "Smaller version of the GRB theme",
|
||||
"language": [
|
||||
"nl",
|
||||
"en"
|
||||
],
|
||||
socialImage: "img.jpg",
|
||||
"version": "0",
|
||||
"startLat": 51.0249,
|
||||
"startLon": 4.026489,
|
||||
"startZoom": 9,
|
||||
"clustering": false,
|
||||
"overrideAll": {
|
||||
"minzoom": 19
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"id": "type_node",
|
||||
source: {
|
||||
osmTags: "type=node"
|
||||
},
|
||||
mapRendering: null,
|
||||
"override": {
|
||||
"calculatedTags": [
|
||||
"_is_part_of_building=feat.get('parent_ways')?.some(p => p.building !== undefined && p.building !== '') ?? false",
|
||||
"_is_part_of_grb_building=feat.get('parent_ways')?.some(p => p['source:geometry:ref'] !== undefined) ?? false",
|
||||
"_is_part_of_building_passage=feat.get('parent_ways')?.some(p => p.tunnel === 'building_passage') ?? false",
|
||||
"_is_part_of_highway=!feat.get('is_part_of_building_passage') && (feat.get('parent_ways')?.some(p => p.highway !== undefined && p.highway !== '') ?? false)",
|
||||
"_is_part_of_landuse=feat.get('parent_ways')?.some(p => (p.landuse !== undefined && p.landuse !== '') || (p.natural !== undefined && p.natural !== '')) ?? false",
|
||||
"_moveable=feat.get('_is_part_of_building') && !feat.get('_is_part_of_grb_building')"
|
||||
],
|
||||
"mapRendering": [
|
||||
{
|
||||
"icon": "square:#cc0",
|
||||
"iconSize": "5,5,center",
|
||||
"location": [
|
||||
"point"
|
||||
]
|
||||
}
|
||||
],
|
||||
"passAllFeatures": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "osm-buildings",
|
||||
"name": "All OSM-buildings",
|
||||
"source": {
|
||||
"osmTags": "building~*",
|
||||
"maxCacheAge": 0
|
||||
},
|
||||
"calculatedTags": [
|
||||
"_surface:strict:=feat.get('_surface')"
|
||||
],
|
||||
"mapRendering": [
|
||||
{
|
||||
"width": {
|
||||
"render": "2",
|
||||
"mappings": [
|
||||
{
|
||||
"if": "fixme~*",
|
||||
"then": "5"
|
||||
}
|
||||
]
|
||||
},
|
||||
"color": {
|
||||
"render": "#00c",
|
||||
"mappings": [
|
||||
{
|
||||
"if": "fixme~*",
|
||||
"then": "#ff00ff"
|
||||
},
|
||||
{
|
||||
"if": "building=house",
|
||||
"then": "#a00"
|
||||
},
|
||||
{
|
||||
"if": "building=shed",
|
||||
"then": "#563e02"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"or": [
|
||||
"building=garage",
|
||||
"building=garages"
|
||||
]
|
||||
},
|
||||
"then": "#f9bfbb"
|
||||
},
|
||||
{
|
||||
"if": "building=yes",
|
||||
"then": "#0774f2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "OSM-gebouw",
|
||||
"tagRenderings": [
|
||||
{
|
||||
"id": "building type",
|
||||
"freeform": {
|
||||
"key": "building"
|
||||
},
|
||||
"render": "The building type is <b>{building}</b>",
|
||||
"question": {
|
||||
"en": "What kind of building is this?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "building=house",
|
||||
"then": "A normal house"
|
||||
},
|
||||
{
|
||||
"if": "building=detached",
|
||||
"then": "A house detached from other building"
|
||||
},
|
||||
{
|
||||
"if": "building=semidetached_house",
|
||||
"then": "A house sharing only one wall with another house"
|
||||
},
|
||||
{
|
||||
"if": "building=apartments",
|
||||
"then": "An apartment building - highrise for living"
|
||||
},
|
||||
{
|
||||
"if": "building=office",
|
||||
"then": "An office building - highrise for work"
|
||||
},
|
||||
{
|
||||
"if": "building=apartments",
|
||||
"then": "An apartment building"
|
||||
},
|
||||
{
|
||||
"if": "building=shed",
|
||||
"then": "A small shed, e.g. in a garden"
|
||||
},
|
||||
{
|
||||
"if": "building=garage",
|
||||
"then": "A single garage to park a car"
|
||||
},
|
||||
{
|
||||
"if": "building=garages",
|
||||
"then": "A building containing only garages; typically they are all identical"
|
||||
},
|
||||
{
|
||||
"if": "building=yes",
|
||||
"then": "A building - no specification"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grb-housenumber",
|
||||
"render": {
|
||||
"nl": "Het huisnummer is <b>{addr:housenumber}</b>"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat is het huisnummer?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "addr:housenumber"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"not:addr:housenumber=yes",
|
||||
"addr:housenumber="
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Geen huisnummer"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grb-unit",
|
||||
"question": "Wat is de wooneenheid-aanduiding?",
|
||||
"render": {
|
||||
"nl": "De wooneenheid-aanduiding is <b>{addr:unit}</b> "
|
||||
},
|
||||
"freeform": {
|
||||
"key": "addr:unit"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "addr:unit=",
|
||||
"then": "Geen wooneenheid-nummer"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grb-street",
|
||||
"render": {
|
||||
"nl": "De straat is <b>{addr:street}</b>"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "addr:street"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat is de straat?"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "grb-fixme",
|
||||
"render": {
|
||||
"nl": "De fixme is <b>{fixme}</b>"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wat zegt de fixme?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "fixme"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"fixme="
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Geen fixme"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grb-min-level",
|
||||
"render": {
|
||||
"nl": "Dit gebouw begint maar op de {building:min_level} verdieping"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Hoeveel verdiepingen ontbreken?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "building:min_level",
|
||||
"type": "pnat"
|
||||
}
|
||||
},
|
||||
"all_tags"
|
||||
],
|
||||
"filter": [
|
||||
{
|
||||
"id": "has-fixme",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "fixme~*",
|
||||
"question": "Heeft een FIXME"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grb",
|
||||
"description": "Geometry which comes from GRB with tools to import them",
|
||||
"source": {
|
||||
"osmTags": {
|
||||
"and": [
|
||||
"HUISNR~*",
|
||||
"man_made!=mast"
|
||||
]
|
||||
},
|
||||
"geoJson": "https://betadata.grbosm.site/grb?bbox={x_min},{y_min},{x_max},{y_max}",
|
||||
"geoJsonZoomLevel": 18,
|
||||
"mercatorCrs": true,
|
||||
"maxCacheAge": 0
|
||||
},
|
||||
"name": "GRB geometries",
|
||||
"title": "GRB outline",
|
||||
"calculatedTags": [
|
||||
"_overlaps_with_buildings=feat.overlapWith('osm-buildings').filter(f => f.feat.properties.id.indexOf('-') < 0)",
|
||||
"_overlaps_with=feat.get('_overlaps_with_buildings').filter(f => f.overlap > 1 /* square meter */ )[0] ?? ''",
|
||||
"_osm_obj:source:ref=feat.get('_overlaps_with')?.feat?.properties['source:geometry:ref']",
|
||||
"_osm_obj:id=feat.get('_overlaps_with')?.feat?.properties?.id",
|
||||
"_osm_obj:source:date=feat.get('_overlaps_with')?.feat?.properties['source:geometry:date'].replace(/\\//g, '-')",
|
||||
"_osm_obj:building=feat.get('_overlaps_with')?.feat?.properties?.building",
|
||||
"_osm_obj:addr:street=(feat.get('_overlaps_with')?.feat?.properties ?? {})['addr:street']",
|
||||
"_osm_obj:addr:housenumber=(feat.get('_overlaps_with')?.feat?.properties ?? {})['addr:housenumber']",
|
||||
"_osm_obj:surface=(feat.get('_overlaps_with')?.feat?.properties ?? {})['_surface:strict']",
|
||||
|
||||
"_overlap_absolute=feat.get('_overlaps_with')?.overlap",
|
||||
"_reverse_overlap_percentage=Math.round(100 * feat.get('_overlap_absolute') / feat.get('_surface'))",
|
||||
"_overlap_percentage=Math.round(100 * feat.get('_overlap_absolute') / feat.get('_osm_obj:surface'))",
|
||||
"_grb_ref=feat.properties['source:geometry:entity'] + '/' + feat.properties['source:geometry:oidn']",
|
||||
"_imported_osm_object_found= feat.properties['_osm_obj:source:ref'] == feat.properties._grb_ref",
|
||||
"_grb_date=feat.properties['source:geometry:date'].replace(/\\//g,'-')",
|
||||
"_imported_osm_still_fresh= feat.properties['_osm_obj:source:date'] == feat.properties._grb_date",
|
||||
"_target_building_type=feat.properties['_osm_obj:building'] === 'yes' ? feat.properties.building : (feat.properties['_osm_obj:building'] ?? feat.properties.building)",
|
||||
"_building:min_level= feat.properties['fixme']?.startsWith('verdieping, correct the building tag, add building:level and building:min_level before upload in JOSM!') ? '1' : ''",
|
||||
"_intersects_with_other_features=feat.intersectionsWith('generic_osm_object').map(f => \"<a href='https://osm.org/\"+f.feat.properties.id+\"' target='_blank'>\" + f.feat.properties.id + \"</a>\").join(', ')"
|
||||
],
|
||||
"tagRenderings": [],
|
||||
"mapRendering": [
|
||||
{
|
||||
"iconSize": "50,50,center",
|
||||
"icon": "./assets/themes/grb_import/housenumber_blank.svg",
|
||||
"location": [
|
||||
"point",
|
||||
"centroid"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
["House replacement with connected node", async () => {
|
||||
|
||||
Minimap.createMiniMap = () => undefined;
|
||||
|
||||
const coordinates = <[number, number][]>[
|
||||
[
|
||||
3.216690793633461,
|
||||
51.21474084112525
|
||||
],
|
||||
[
|
||||
3.2167256623506546,
|
||||
51.214696737309964
|
||||
],
|
||||
[
|
||||
3.2169999182224274,
|
||||
51.214768983537674
|
||||
],
|
||||
[
|
||||
3.2169650495052338,
|
||||
51.21480720678671
|
||||
],
|
||||
[
|
||||
3.2169368863105774,
|
||||
51.21480090625335
|
||||
],
|
||||
[
|
||||
3.2169489562511444,
|
||||
51.21478074454077
|
||||
],
|
||||
[
|
||||
3.216886594891548,
|
||||
51.214765203214625
|
||||
],
|
||||
[
|
||||
3.2168812304735184,
|
||||
51.21477192378873
|
||||
],
|
||||
[
|
||||
3.2168644666671753,
|
||||
51.214768983537674
|
||||
],
|
||||
[
|
||||
3.2168537378311157,
|
||||
51.21478746511261
|
||||
],
|
||||
[
|
||||
3.216690793633461,
|
||||
51.21474084112525
|
||||
]
|
||||
]
|
||||
|
||||
const targetFeature = {
|
||||
type: "Feature",
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: "Polygon",
|
||||
coordinates: [coordinates]
|
||||
}
|
||||
}
|
||||
|
||||
const wayId = "way/160909312"
|
||||
|
||||
Utils.injectJsonDownloadForTests(
|
||||
"https://www.openstreetmap.org/api/0.6/map.json?bbox=3.2166673243045807,51.21467321525788,3.217007964849472,51.21482442824023",
|
||||
{
|
||||
"version": "0.6",
|
||||
"generator": "CGImap 0.8.6 (1549677 spike-06.openstreetmap.org)",
|
||||
"copyright": "OpenStreetMap and contributors",
|
||||
"attribution": "http://www.openstreetmap.org/copyright",
|
||||
"license": "http://opendatacommons.org/licenses/odbl/1-0/",
|
||||
"bounds": {"minlat": 51.2146732, "minlon": 3.2166673, "maxlat": 51.2148244, "maxlon": 3.217008},
|
||||
"elements": [{
|
||||
"type": "node",
|
||||
"id": 1612385157,
|
||||
"lat": 51.2148016,
|
||||
"lon": 3.2168453,
|
||||
"timestamp": "2018-04-30T12:26:00Z",
|
||||
"version": 3,
|
||||
"changeset": 58553478,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1728816256,
|
||||
"lat": 51.2147111,
|
||||
"lon": 3.2170233,
|
||||
"timestamp": "2017-07-18T22:52:44Z",
|
||||
"version": 2,
|
||||
"changeset": 50391526,
|
||||
"user": "catweazle67",
|
||||
"uid": 1976209
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1728816287,
|
||||
"lat": 51.2146408,
|
||||
"lon": 3.2167601,
|
||||
"timestamp": "2021-10-29T16:24:43Z",
|
||||
"version": 3,
|
||||
"changeset": 113131915,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1728823481,
|
||||
"lat": 51.2146968,
|
||||
"lon": 3.2167242,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 5,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1728823499,
|
||||
"lat": 51.2147127,
|
||||
"lon": 3.2170302,
|
||||
"timestamp": "2017-07-18T22:52:45Z",
|
||||
"version": 2,
|
||||
"changeset": 50391526,
|
||||
"user": "catweazle67",
|
||||
"uid": 1976209
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1728823501,
|
||||
"lat": 51.2148696,
|
||||
"lon": 3.2168941,
|
||||
"timestamp": "2017-07-18T22:52:45Z",
|
||||
"version": 2,
|
||||
"changeset": 50391526,
|
||||
"user": "catweazle67",
|
||||
"uid": 1976209
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1728823514,
|
||||
"lat": 51.2147863,
|
||||
"lon": 3.2168551,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 5,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1728823522,
|
||||
"lat": 51.2148489,
|
||||
"lon": 3.2169012,
|
||||
"timestamp": "2017-07-18T22:52:45Z",
|
||||
"version": 2,
|
||||
"changeset": 50391526,
|
||||
"user": "catweazle67",
|
||||
"uid": 1976209
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1728823523,
|
||||
"lat": 51.2147578,
|
||||
"lon": 3.2169995,
|
||||
"timestamp": "2017-07-18T22:52:45Z",
|
||||
"version": 2,
|
||||
"changeset": 50391526,
|
||||
"user": "catweazle67",
|
||||
"uid": 1976209
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1728823543,
|
||||
"lat": 51.2148075,
|
||||
"lon": 3.2166445,
|
||||
"timestamp": "2017-07-18T22:52:46Z",
|
||||
"version": 3,
|
||||
"changeset": 50391526,
|
||||
"user": "catweazle67",
|
||||
"uid": 1976209
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1728823544,
|
||||
"lat": 51.2148553,
|
||||
"lon": 3.2169315,
|
||||
"timestamp": "2017-07-18T22:52:46Z",
|
||||
"version": 2,
|
||||
"changeset": 50391526,
|
||||
"user": "catweazle67",
|
||||
"uid": 1976209
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1728823549,
|
||||
"lat": 51.2147401,
|
||||
"lon": 3.2168877,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 5,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4978288376,
|
||||
"lat": 51.2147306,
|
||||
"lon": 3.2168928,
|
||||
"timestamp": "2017-07-18T22:52:21Z",
|
||||
"version": 1,
|
||||
"changeset": 50391526,
|
||||
"user": "catweazle67",
|
||||
"uid": 1976209
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4978288381,
|
||||
"lat": 51.2147638,
|
||||
"lon": 3.2168856,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 4,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4978288382,
|
||||
"lat": 51.2148189,
|
||||
"lon": 3.216912,
|
||||
"timestamp": "2017-07-18T22:52:21Z",
|
||||
"version": 1,
|
||||
"changeset": 50391526,
|
||||
"user": "catweazle67",
|
||||
"uid": 1976209
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4978288385,
|
||||
"lat": 51.2148835,
|
||||
"lon": 3.2170623,
|
||||
"timestamp": "2017-07-18T22:52:21Z",
|
||||
"version": 1,
|
||||
"changeset": 50391526,
|
||||
"user": "catweazle67",
|
||||
"uid": 1976209
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4978288387,
|
||||
"lat": 51.2148904,
|
||||
"lon": 3.2171037,
|
||||
"timestamp": "2017-07-18T22:52:21Z",
|
||||
"version": 1,
|
||||
"changeset": 50391526,
|
||||
"user": "catweazle67",
|
||||
"uid": 1976209
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4978289383,
|
||||
"lat": 51.2147678,
|
||||
"lon": 3.2169969,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 4,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4978289384,
|
||||
"lat": 51.2147684,
|
||||
"lon": 3.2168674,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 4,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4978289386,
|
||||
"lat": 51.2147716,
|
||||
"lon": 3.2168811,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 4,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4978289388,
|
||||
"lat": 51.2148115,
|
||||
"lon": 3.216966,
|
||||
"timestamp": "2021-11-02T23:38:13Z",
|
||||
"version": 7,
|
||||
"changeset": 113306325,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4978289391,
|
||||
"lat": 51.2148019,
|
||||
"lon": 3.2169194,
|
||||
"timestamp": "2017-07-18T22:52:21Z",
|
||||
"version": 1,
|
||||
"changeset": 50391526,
|
||||
"user": "catweazle67",
|
||||
"uid": 1976209
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 9219974337,
|
||||
"lat": 51.2148449,
|
||||
"lon": 3.2171278,
|
||||
"timestamp": "2021-11-02T23:40:52Z",
|
||||
"version": 1,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 9219979643,
|
||||
"lat": 51.2147405,
|
||||
"lon": 3.216693,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 1,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 9219979646,
|
||||
"lat": 51.2148043,
|
||||
"lon": 3.2169312,
|
||||
"timestamp": "2021-11-02T23:38:13Z",
|
||||
"version": 2,
|
||||
"changeset": 113306325,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 9219979647,
|
||||
"lat": 51.2147792,
|
||||
"lon": 3.2169466,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 1,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "way",
|
||||
"id": 160909311,
|
||||
"timestamp": "2021-12-23T12:03:37Z",
|
||||
"version": 6,
|
||||
"changeset": 115295690,
|
||||
"user": "s8evq",
|
||||
"uid": 3710738,
|
||||
"nodes": [1728823481, 1728823549, 4978288376, 1728823523, 1728823499, 1728816256, 1728816287, 1728823481],
|
||||
"tags": {
|
||||
"addr:city": "Brugge",
|
||||
"addr:country": "BE",
|
||||
"addr:housenumber": "106",
|
||||
"addr:postcode": "8000",
|
||||
"addr:street": "Ezelstraat",
|
||||
"building": "house",
|
||||
"source:geometry:date": "2015-07-09",
|
||||
"source:geometry:ref": "Gbg/2391617"
|
||||
}
|
||||
}, {
|
||||
"type": "way",
|
||||
"id": 160909312,
|
||||
"timestamp": "2021-11-02T23:38:13Z",
|
||||
"version": 4,
|
||||
"changeset": 113306325,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858,
|
||||
"nodes": [9219979643, 1728823481, 1728823549, 4978289383, 4978289388, 9219979646, 9219979647, 4978288381, 4978289386, 4978289384, 1728823514, 9219979643],
|
||||
"tags": {
|
||||
"addr:city": "Brugge",
|
||||
"addr:country": "BE",
|
||||
"addr:housenumber": "108",
|
||||
"addr:postcode": "8000",
|
||||
"addr:street": "Ezelstraat",
|
||||
"building": "house",
|
||||
"source:geometry:date": "2018-10-02",
|
||||
"source:geometry:ref": "Gbg/5926383"
|
||||
}
|
||||
}, {
|
||||
"type": "way",
|
||||
"id": 160909315,
|
||||
"timestamp": "2021-12-23T12:03:37Z",
|
||||
"version": 8,
|
||||
"changeset": 115295690,
|
||||
"user": "s8evq",
|
||||
"uid": 3710738,
|
||||
"nodes": [1728823543, 1728823501, 1728823522, 4978288382, 1612385157, 1728823514, 9219979643, 1728823543],
|
||||
"tags": {
|
||||
"addr:city": "Brugge",
|
||||
"addr:country": "BE",
|
||||
"addr:housenumber": "110",
|
||||
"addr:postcode": "8000",
|
||||
"addr:street": "Ezelstraat",
|
||||
"building": "house",
|
||||
"name": "La Style",
|
||||
"shop": "hairdresser",
|
||||
"source:geometry:date": "2015-07-09",
|
||||
"source:geometry:ref": "Gbg/5260837"
|
||||
}
|
||||
}, {
|
||||
"type": "way",
|
||||
"id": 508533816,
|
||||
"timestamp": "2021-12-23T12:03:37Z",
|
||||
"version": 7,
|
||||
"changeset": 115295690,
|
||||
"user": "s8evq",
|
||||
"uid": 3710738,
|
||||
"nodes": [4978288387, 4978288385, 1728823544, 1728823522, 4978288382, 4978289391, 9219979646, 4978289388, 9219974337, 4978288387],
|
||||
"tags": {
|
||||
"building": "yes",
|
||||
"source:geometry:date": "2015-07-09",
|
||||
"source:geometry:ref": "Gbg/5260790"
|
||||
}
|
||||
}]
|
||||
}
|
||||
)
|
||||
|
||||
Utils.injectJsonDownloadForTests(
|
||||
"https://www.openstreetmap.org/api/0.6/way/160909312/full",
|
||||
{
|
||||
"version": "0.6",
|
||||
"generator": "CGImap 0.8.6 (2407324 spike-06.openstreetmap.org)",
|
||||
"copyright": "OpenStreetMap and contributors",
|
||||
"attribution": "http://www.openstreetmap.org/copyright",
|
||||
"license": "http://opendatacommons.org/licenses/odbl/1-0/",
|
||||
"elements": [{
|
||||
"type": "node",
|
||||
"id": 1728823481,
|
||||
"lat": 51.2146968,
|
||||
"lon": 3.2167242,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 5,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1728823514,
|
||||
"lat": 51.2147863,
|
||||
"lon": 3.2168551,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 5,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 1728823549,
|
||||
"lat": 51.2147401,
|
||||
"lon": 3.2168877,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 5,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4978288381,
|
||||
"lat": 51.2147638,
|
||||
"lon": 3.2168856,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 4,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4978289383,
|
||||
"lat": 51.2147678,
|
||||
"lon": 3.2169969,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 4,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4978289384,
|
||||
"lat": 51.2147684,
|
||||
"lon": 3.2168674,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 4,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4978289386,
|
||||
"lat": 51.2147716,
|
||||
"lon": 3.2168811,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 4,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 4978289388,
|
||||
"lat": 51.2148115,
|
||||
"lon": 3.216966,
|
||||
"timestamp": "2021-11-02T23:38:13Z",
|
||||
"version": 7,
|
||||
"changeset": 113306325,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 9219979643,
|
||||
"lat": 51.2147405,
|
||||
"lon": 3.216693,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 1,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 9219979646,
|
||||
"lat": 51.2148043,
|
||||
"lon": 3.2169312,
|
||||
"timestamp": "2021-11-02T23:38:13Z",
|
||||
"version": 2,
|
||||
"changeset": 113306325,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "node",
|
||||
"id": 9219979647,
|
||||
"lat": 51.2147792,
|
||||
"lon": 3.2169466,
|
||||
"timestamp": "2021-11-02T23:37:11Z",
|
||||
"version": 1,
|
||||
"changeset": 113305401,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858
|
||||
}, {
|
||||
"type": "way",
|
||||
"id": 160909312,
|
||||
"timestamp": "2021-11-02T23:38:13Z",
|
||||
"version": 4,
|
||||
"changeset": 113306325,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858,
|
||||
"nodes": [9219979643, 1728823481, 1728823549, 4978289383, 4978289388, 9219979646, 9219979647, 4978288381, 4978289386, 4978289384, 1728823514, 9219979643],
|
||||
"tags": {
|
||||
"addr:city": "Brugge",
|
||||
"addr:country": "BE",
|
||||
"addr:housenumber": "108",
|
||||
"addr:postcode": "8000",
|
||||
"addr:street": "Ezelstraat",
|
||||
"building": "house",
|
||||
"source:geometry:date": "2018-10-02",
|
||||
"source:geometry:ref": "Gbg/5926383"
|
||||
}
|
||||
}]
|
||||
}
|
||||
)
|
||||
Utils.injectJsonDownloadForTests("https://raw.githubusercontent.com/pietervdvn/MapComplete-data/main/latlon2country/0.0.0.json", "be")
|
||||
|
||||
const layout = new LayoutConfig(<any>ReplaceGeometrySpec.grbStripped)
|
||||
|
||||
|
||||
const state = new State(layout)
|
||||
State.state = state;
|
||||
const bbox = new BBox(
|
||||
[[
|
||||
3.2166673243045807,
|
||||
51.21467321525788
|
||||
],
|
||||
[
|
||||
3.217007964849472,
|
||||
51.21482442824023
|
||||
]
|
||||
])
|
||||
const url = `https://www.openstreetmap.org/api/0.6/map.json?bbox=${bbox.minLon},${bbox.minLat},${bbox.maxLon},${bbox.maxLat}`
|
||||
const data = await Utils.downloadJson(url)
|
||||
|
||||
state.featurePipeline.fullNodeDatabase.handleOsmJson(data, 0)
|
||||
|
||||
|
||||
const action = new ReplaceGeometryAction(state, targetFeature, wayId, {
|
||||
theme: "test"
|
||||
}
|
||||
)
|
||||
|
||||
const closestIds = await action.GetClosestIds()
|
||||
T.listIdentical<number>(
|
||||
[9219979643,
|
||||
1728823481,
|
||||
4978289383,
|
||||
4978289388,
|
||||
9219979646,
|
||||
9219979647,
|
||||
4978288381,
|
||||
4978289386,
|
||||
4978289384,
|
||||
1728823514,
|
||||
undefined],
|
||||
closestIds.closestIds
|
||||
);
|
||||
|
||||
T.equals(1, closestIds.reprojectedNodes.size, "Expected only a single reprojected node");
|
||||
const reproj = closestIds.reprojectedNodes.get(1728823549)
|
||||
T.equals(1, reproj.projectAfterIndex)
|
||||
T.equals(3.2168880864669203, reproj.newLon);
|
||||
T.equals(51.214739524104694, reproj.newLat);
|
||||
T.equals(0, closestIds.detachedNodes.size)
|
||||
const changes = await action.Perform(state.changes)
|
||||
T.listIdentical([[3.216690793633461, 51.21474084112525], [3.2167256623506546, 51.214696737309964], [3.2168880864669203, 51.214739524104694], [3.2169999182224274, 51.214768983537674], [3.2169650495052338, 51.21480720678671], [3.2169368863105774, 51.21480090625335], [3.2169489562511444, 51.21478074454077], [3.216886594891548, 51.214765203214625], [3.2168812304735184, 51.21477192378873], [3.2168644666671753, 51.214768983537674], [3.2168537378311157, 51.21478746511261], [3.216690793633461, 51.21474084112525]],
|
||||
changes[11].changes["coordinates"])
|
||||
|
||||
}],
|
||||
]);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
676
test/Tag.spec.ts
676
test/Tag.spec.ts
|
@ -1,676 +0,0 @@
|
|||
import {Utils} from "../Utils";
|
||||
import {equal} from "assert";
|
||||
import T from "./TestHelper";
|
||||
import Locale from "../UI/i18n/Locale";
|
||||
import Translations from "../UI/i18n/Translations";
|
||||
import {Translation} from "../UI/i18n/Translation";
|
||||
import {OH, OpeningHour} from "../UI/OpeningHours/OpeningHours";
|
||||
import {Tag} from "../Logic/Tags/Tag";
|
||||
import {And} from "../Logic/Tags/And";
|
||||
import {TagUtils} from "../Logic/Tags/TagUtils";
|
||||
import TagRenderingConfig from "../Models/ThemeConfig/TagRenderingConfig";
|
||||
import {TagsFilter} from "../Logic/Tags/TagsFilter";
|
||||
import {Or} from "../Logic/Tags/Or";
|
||||
import {RegexTag} from "../Logic/Tags/RegexTag";
|
||||
|
||||
export default class TagSpec extends T {
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
["Tag replacement works in translation", () => {
|
||||
const tr = new Translation({
|
||||
"en": "Test {key} abc"
|
||||
}).replace("{key}", "value");
|
||||
equal(tr.txt, "Test value abc");
|
||||
|
||||
}],
|
||||
["Optimize tags", () => {
|
||||
|
||||
let t : TagsFilter= new And(
|
||||
[
|
||||
new And([
|
||||
new Tag("x", "y")
|
||||
]),
|
||||
new Tag("a", "b")
|
||||
]
|
||||
)
|
||||
let opt =<TagsFilter> t.optimize()
|
||||
console.log(TagUtils.toString(opt))
|
||||
T.equals(`a=b&x=y`,TagUtils.toString(opt), "Optimization failed")
|
||||
|
||||
|
||||
// foo&bar & (x=y | a=b) & (x=y | c=d) & foo=bar is equivalent too foo=bar & ((x=y) | (a=b & c=d))
|
||||
t = new And([
|
||||
new Tag("foo","bar"),
|
||||
new Or([
|
||||
new Tag("x", "y"),
|
||||
new Tag("a", "b")
|
||||
]),
|
||||
new Or([
|
||||
new Tag("x", "y"),
|
||||
new Tag("c", "d")
|
||||
])
|
||||
])
|
||||
opt =<TagsFilter> t.optimize()
|
||||
console.log(TagUtils.toString(opt))
|
||||
T.equals(TagUtils.toString(opt), "foo=bar& (x=y| (a=b&c=d) )")
|
||||
|
||||
t = new Or([
|
||||
new Tag("foo","bar"),
|
||||
new And([
|
||||
new Tag("foo", "bar"),
|
||||
new Tag("x", "y"),
|
||||
])
|
||||
])
|
||||
opt =<TagsFilter> t.optimize()
|
||||
console.log(TagUtils.toString(opt))
|
||||
T.equals("foo=bar", TagUtils.toString(opt), "Optimizing away an unneeded factor failed")
|
||||
|
||||
|
||||
t = new And([
|
||||
new RegexTag("x","y"),
|
||||
new Tag("a","b")
|
||||
])
|
||||
opt =<TagsFilter> t.optimize()
|
||||
T.equals("a=b&x~^y$", TagUtils.toString(opt), "Regexes go to the end")
|
||||
|
||||
t = new And([
|
||||
new Tag("bicycle","yes"),
|
||||
new Tag("amenity","binoculars")
|
||||
])
|
||||
opt =<TagsFilter> t.optimize()
|
||||
T.equals("amenity=binoculars&bicycle=yes", TagUtils.toString(opt), "Common keys go to the end")
|
||||
|
||||
|
||||
|
||||
|
||||
const filter = TagUtils.Tag( {or: [
|
||||
{
|
||||
"and": [
|
||||
{
|
||||
"or": ["amenity=charging_station","disused:amenity=charging_station","planned:amenity=charging_station","construction:amenity=charging_station"]
|
||||
},
|
||||
"bicycle=yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"and": [
|
||||
{
|
||||
"or": ["amenity=charging_station","disused:amenity=charging_station","planned:amenity=charging_station","construction:amenity=charging_station"]
|
||||
},
|
||||
]
|
||||
},
|
||||
"amenity=toilets",
|
||||
"amenity=bench",
|
||||
"leisure=picnic_table",
|
||||
{
|
||||
"and": [
|
||||
"tower:type=observation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"and": [
|
||||
"amenity=bicycle_repair_station"
|
||||
]
|
||||
},
|
||||
{
|
||||
"and": [
|
||||
{
|
||||
"or": [
|
||||
"amenity=bicycle_rental",
|
||||
"bicycle_rental~*",
|
||||
"service:bicycle:rental=yes",
|
||||
"rental~.*bicycle.*"
|
||||
]
|
||||
},
|
||||
"bicycle_rental!=docking_station"
|
||||
]
|
||||
},
|
||||
{
|
||||
"and": [
|
||||
"leisure=playground",
|
||||
"playground!=forest"
|
||||
]
|
||||
}
|
||||
]});
|
||||
|
||||
opt = <TagsFilter> filter.optimize()
|
||||
console.log(TagUtils.toString(opt))
|
||||
T.equals(("amenity=charging_station|" +
|
||||
"amenity=toilets|" +
|
||||
"amenity=bench|" +
|
||||
"amenity=bicycle_repair_station" +
|
||||
"|construction:amenity=charging_station|" +
|
||||
"disused:amenity=charging_station|" +
|
||||
"leisure=picnic_table|" +
|
||||
"planned:amenity=charging_station|" +
|
||||
"tower:type=observation| " +
|
||||
"( (amenity=bicycle_rental|service:bicycle:rental=yes|bicycle_rental~^..*$|rental~^.*bicycle.*$) &bicycle_rental!~^docking_station$) |" +
|
||||
" (leisure=playground&playground!~^forest$)").replace(/ /g, ""),
|
||||
TagUtils.toString(opt).replace(/ /g, ""), "Advanced case failed")
|
||||
}],
|
||||
|
||||
|
||||
["Parse tag config", (() => {
|
||||
const tag = TagUtils.Tag("key=value") as Tag;
|
||||
equal(tag.key, "key");
|
||||
equal(tag.value, "value");
|
||||
equal(tag.matchesProperties({"key": "value"}), true)
|
||||
equal(tag.matchesProperties({"key": "z"}), false)
|
||||
equal(tag.matchesProperties({"key": ""}), false)
|
||||
equal(tag.matchesProperties({"other_key": ""}), false)
|
||||
equal(tag.matchesProperties({"other_key": "value"}), false)
|
||||
|
||||
const isEmpty = TagUtils.Tag("key=") as Tag;
|
||||
equal(isEmpty.matchesProperties({"key": "value"}), false)
|
||||
equal(isEmpty.matchesProperties({"key": ""}), true)
|
||||
equal(isEmpty.matchesProperties({"other_key": ""}), true)
|
||||
equal(isEmpty.matchesProperties({"other_key": "value"}), true)
|
||||
|
||||
const isNotEmpty = TagUtils.Tag("key!=");
|
||||
equal(isNotEmpty.matchesProperties({"key": "value"}), true)
|
||||
equal(isNotEmpty.matchesProperties({"key": "other_value"}), true)
|
||||
equal(isNotEmpty.matchesProperties({"key": ""}), false)
|
||||
equal(isNotEmpty.matchesProperties({"other_key": ""}), false)
|
||||
equal(isNotEmpty.matchesProperties({"other_key": "value"}), false)
|
||||
|
||||
|
||||
const and = TagUtils.Tag({"and": ["key=value", "x=y"]}) as And;
|
||||
equal((and.and[0] as Tag).key, "key");
|
||||
equal((and.and[1] as Tag).value, "y");
|
||||
|
||||
|
||||
const notReg = TagUtils.Tag("x!~y") as And;
|
||||
equal(notReg.matchesProperties({"x": "y"}), false)
|
||||
equal(notReg.matchesProperties({"x": "z"}), true)
|
||||
equal(notReg.matchesProperties({"x": ""}), true)
|
||||
equal(notReg.matchesProperties({}), true)
|
||||
|
||||
const noMatch = TagUtils.Tag("key!=value") as Tag;
|
||||
equal(noMatch.matchesProperties({"key": "value"}), false)
|
||||
equal(noMatch.matchesProperties({"key": "otherValue"}), true)
|
||||
equal(noMatch.matchesProperties({"key": ""}), true)
|
||||
equal(noMatch.matchesProperties({"otherKey": ""}), true)
|
||||
|
||||
|
||||
const multiMatch = TagUtils.Tag("vending~.*bicycle_tube.*") as Tag;
|
||||
equal(multiMatch.matchesProperties({"vending": "bicycle_tube"}), true)
|
||||
equal(multiMatch.matchesProperties({"vending": "something;bicycle_tube"}), true)
|
||||
equal(multiMatch.matchesProperties({"vending": "bicycle_tube;something"}), true)
|
||||
equal(multiMatch.matchesProperties({"vending": "xyz;bicycle_tube;something"}), true)
|
||||
|
||||
const nameStartsWith = TagUtils.Tag("name~[sS]peelbos.*")
|
||||
equal(nameStartsWith.matchesProperties({"name": "Speelbos Sint-Anna"}), true)
|
||||
equal(nameStartsWith.matchesProperties({"name": "speelbos Sint-Anna"}), true)
|
||||
equal(nameStartsWith.matchesProperties({"name": "Sint-Anna"}), false)
|
||||
equal(nameStartsWith.matchesProperties({"name": ""}), false)
|
||||
|
||||
|
||||
const assign = TagUtils.Tag("survey:date:={_date:now}")
|
||||
equal(assign.matchesProperties({"survey:date": "2021-03-29", "_date:now": "2021-03-29"}), true);
|
||||
equal(assign.matchesProperties({"survey:date": "2021-03-29", "_date:now": "2021-01-01"}), false);
|
||||
equal(assign.matchesProperties({"survey:date": "2021-03-29"}), false);
|
||||
equal(assign.matchesProperties({"_date:now": "2021-03-29"}), false);
|
||||
equal(assign.matchesProperties({"some_key": "2021-03-29"}), false);
|
||||
|
||||
const notEmptyList = TagUtils.Tag("xyz!~\\[\\]")
|
||||
equal(notEmptyList.matchesProperties({"xyz": undefined}), true);
|
||||
equal(notEmptyList.matchesProperties({"xyz": "[]"}), false);
|
||||
equal(notEmptyList.matchesProperties({"xyz": "[\"abc\"]"}), true);
|
||||
|
||||
let compare = TagUtils.Tag("key<=5")
|
||||
equal(compare.matchesProperties({"key": undefined}), false);
|
||||
equal(compare.matchesProperties({"key": "6"}), false);
|
||||
equal(compare.matchesProperties({"key": "5"}), true);
|
||||
equal(compare.matchesProperties({"key": "4"}), true);
|
||||
|
||||
|
||||
compare = TagUtils.Tag("key<5")
|
||||
equal(compare.matchesProperties({"key": undefined}), false);
|
||||
equal(compare.matchesProperties({"key": "6"}), false);
|
||||
equal(compare.matchesProperties({"key": "5"}), false);
|
||||
equal(compare.matchesProperties({"key": "4.2"}), true);
|
||||
|
||||
compare = TagUtils.Tag("key>5")
|
||||
equal(compare.matchesProperties({"key": undefined}), false);
|
||||
equal(compare.matchesProperties({"key": "6"}), true);
|
||||
equal(compare.matchesProperties({"key": "5"}), false);
|
||||
equal(compare.matchesProperties({"key": "4.2"}), false);
|
||||
compare = TagUtils.Tag("key>=5")
|
||||
equal(compare.matchesProperties({"key": undefined}), false);
|
||||
equal(compare.matchesProperties({"key": "6"}), true);
|
||||
equal(compare.matchesProperties({"key": "5"}), true);
|
||||
equal(compare.matchesProperties({"key": "4.2"}), false);
|
||||
|
||||
const importMatch = TagUtils.Tag("tags~(^|.*;)amenity=public_bookcase($|;.*)")
|
||||
equal(importMatch.matchesProperties({"tags": "amenity=public_bookcase;name=test"}), true)
|
||||
equal(importMatch.matchesProperties({"tags": "amenity=public_bookcase"}), true)
|
||||
equal(importMatch.matchesProperties({"tags": "name=test;amenity=public_bookcase"}), true)
|
||||
equal(importMatch.matchesProperties({"tags": "amenity=bench"}), false)
|
||||
|
||||
})],
|
||||
["Is equivalent test", (() => {
|
||||
|
||||
const t0 = new And([
|
||||
new Tag("valves:special", "A"),
|
||||
new Tag("valves", "A")
|
||||
])
|
||||
const t1 = new And([
|
||||
new Tag("valves", "A")
|
||||
])
|
||||
const t2 = new And([
|
||||
new Tag("valves", "B")
|
||||
])
|
||||
equal(true, t0.isEquivalent(t0))
|
||||
equal(true, t1.isEquivalent(t1))
|
||||
equal(true, t2.isEquivalent(t2))
|
||||
|
||||
equal(false, t0.isEquivalent(t1))
|
||||
equal(false, t0.isEquivalent(t2))
|
||||
equal(false, t1.isEquivalent(t0))
|
||||
|
||||
equal(false, t1.isEquivalent(t2))
|
||||
equal(false, t2.isEquivalent(t0))
|
||||
equal(false, t2.isEquivalent(t1))
|
||||
})],
|
||||
["Parse translation map", (() => {
|
||||
|
||||
const json: any = {"en": "English", "nl": "Nederlands"};
|
||||
const translation = Translations.WT(new Translation(json));
|
||||
Locale.language.setData("en");
|
||||
equal(translation.txt, "English");
|
||||
Locale.language.setData("nl");
|
||||
equal(translation.txt, "Nederlands");
|
||||
})],
|
||||
["Parse tag rendering", (() => {
|
||||
Locale.language.setData("nl");
|
||||
const tr = new TagRenderingConfig({
|
||||
render: ({"en": "Name is {name}", "nl": "Ook een {name}"} as any),
|
||||
question: "Wat is de naam van dit object?",
|
||||
freeform: {
|
||||
key: "name",
|
||||
},
|
||||
|
||||
mappings: [
|
||||
{
|
||||
if: "noname=yes",
|
||||
"then": "Has no name"
|
||||
}
|
||||
],
|
||||
condition: "x="
|
||||
}, "Tests");
|
||||
|
||||
equal(undefined, tr.GetRenderValue({"foo": "bar"}));
|
||||
equal("Has no name", tr.GetRenderValue({"noname": "yes"})?.txt);
|
||||
equal("Ook een {name}", tr.GetRenderValue({"name": "xyz"})?.txt);
|
||||
equal(undefined, tr.GetRenderValue({"foo": "bar"}));
|
||||
|
||||
})],
|
||||
[
|
||||
"Empty match test",
|
||||
() => {
|
||||
const t = new Tag("key", "");
|
||||
equal(false, t.matchesProperties({"key": "somevalue"}))
|
||||
}
|
||||
],
|
||||
[
|
||||
"Test not with overpass",
|
||||
() => {
|
||||
const t = {
|
||||
and: [
|
||||
"boundary=protected_area",
|
||||
"protect_class!=98"
|
||||
]
|
||||
}
|
||||
const filter = TagUtils.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 = TagUtils.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 = TagUtils.Tag(orInOr).asOverpass()
|
||||
equal(3, overpassOrInor.length)
|
||||
}
|
||||
],
|
||||
[
|
||||
"Test regex to overpass",() => {
|
||||
/*(Specifiation to parse, expected value for new RegexTag(spec).asOverpass()[0]) */
|
||||
[["a~*", `"a"`],
|
||||
["a~[xyz]",`"a"~"^[xyz]$"`]].forEach(([spec, expected]) =>{
|
||||
T.equals(`[${expected}]`, TagUtils.Tag(
|
||||
spec
|
||||
).asOverpass()[0], "RegexRendering failed")
|
||||
} )
|
||||
}
|
||||
],
|
||||
[
|
||||
"Merge touching opening hours",
|
||||
() => {
|
||||
const oh1: OpeningHour = {
|
||||
weekday: 0,
|
||||
startHour: 10,
|
||||
startMinutes: 0,
|
||||
endHour: 11,
|
||||
endMinutes: 0
|
||||
};
|
||||
const oh0: OpeningHour = {
|
||||
weekday: 0,
|
||||
startHour: 11,
|
||||
startMinutes: 0,
|
||||
endHour: 12,
|
||||
endMinutes: 0
|
||||
};
|
||||
|
||||
const merged = OH.MergeTimes([oh0, oh1]);
|
||||
const r = merged[0];
|
||||
equal(merged.length, 1);
|
||||
equal(r.startHour, 10);
|
||||
equal(r.endHour, 12)
|
||||
|
||||
}
|
||||
],
|
||||
[
|
||||
"Merge overlapping opening hours",
|
||||
() => {
|
||||
const oh1: OpeningHour = {
|
||||
weekday: 0,
|
||||
startHour: 10,
|
||||
startMinutes: 0,
|
||||
endHour: 11,
|
||||
endMinutes: 0
|
||||
};
|
||||
const oh0: OpeningHour = {
|
||||
weekday: 0,
|
||||
startHour: 10,
|
||||
startMinutes: 30,
|
||||
endHour: 12,
|
||||
endMinutes: 0
|
||||
};
|
||||
|
||||
const merged = OH.MergeTimes([oh0, oh1]);
|
||||
const r = merged[0];
|
||||
equal(merged.length, 1);
|
||||
equal(r.startHour, 10);
|
||||
equal(r.endHour, 12)
|
||||
|
||||
}],
|
||||
["Parse OH 1", () => {
|
||||
const rules = OH.ParseRule("11:00-19:00");
|
||||
equal(rules.length, 7);
|
||||
equal(rules[0].weekday, 0);
|
||||
equal(rules[0].startHour, 11);
|
||||
equal(rules[3].endHour, 19);
|
||||
|
||||
}],
|
||||
["Parse OH 2", () => {
|
||||
const rules = OH.ParseRule("Mo-Th 11:00-19:00");
|
||||
equal(rules.length, 4);
|
||||
equal(rules[0].weekday, 0);
|
||||
equal(rules[0].startHour, 11);
|
||||
equal(rules[3].endHour, 19);
|
||||
}],
|
||||
["JOIN OH 1", () => {
|
||||
const rules = OH.ToString([
|
||||
{
|
||||
weekday: 0,
|
||||
endHour: 12,
|
||||
endMinutes: 0,
|
||||
startHour: 10,
|
||||
startMinutes: 0
|
||||
},
|
||||
{
|
||||
weekday: 0,
|
||||
endHour: 17,
|
||||
endMinutes: 0,
|
||||
startHour: 13,
|
||||
startMinutes: 0
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
weekday: 1,
|
||||
endHour: 17,
|
||||
endMinutes: 0,
|
||||
startHour: 13,
|
||||
startMinutes: 0
|
||||
}, {
|
||||
weekday: 1,
|
||||
endHour: 12,
|
||||
endMinutes: 0,
|
||||
startHour: 10,
|
||||
startMinutes: 0
|
||||
},
|
||||
|
||||
]);
|
||||
equal(rules, "Mo-Tu 10:00-12:00, 13:00-17:00");
|
||||
}],
|
||||
["JOIN OH 2", () => {
|
||||
const rules = OH.ToString([
|
||||
|
||||
{
|
||||
weekday: 1,
|
||||
endHour: 17,
|
||||
endMinutes: 0,
|
||||
startHour: 13,
|
||||
startMinutes: 0
|
||||
}, {
|
||||
weekday: 1,
|
||||
endHour: 12,
|
||||
endMinutes: 0,
|
||||
startHour: 10,
|
||||
startMinutes: 0
|
||||
},
|
||||
|
||||
]);
|
||||
equal(rules, "Tu 10:00-12:00, 13:00-17:00");
|
||||
}],
|
||||
["JOIN OH 3", () => {
|
||||
const rules = OH.ToString([
|
||||
|
||||
{
|
||||
weekday: 3,
|
||||
endHour: 17,
|
||||
endMinutes: 0,
|
||||
startHour: 13,
|
||||
startMinutes: 0
|
||||
}, {
|
||||
weekday: 1,
|
||||
endHour: 12,
|
||||
endMinutes: 0,
|
||||
startHour: 10,
|
||||
startMinutes: 0
|
||||
},
|
||||
|
||||
]);
|
||||
equal(rules, "Tu 10:00-12:00; Th 13:00-17:00");
|
||||
}],
|
||||
["JOIN OH 3", () => {
|
||||
const rules = OH.ToString([
|
||||
|
||||
{
|
||||
weekday: 6,
|
||||
endHour: 17,
|
||||
endMinutes: 0,
|
||||
startHour: 13,
|
||||
startMinutes: 0
|
||||
}, {
|
||||
weekday: 1,
|
||||
endHour: 12,
|
||||
endMinutes: 0,
|
||||
startHour: 10,
|
||||
startMinutes: 0
|
||||
},
|
||||
|
||||
]);
|
||||
equal(rules, "Tu 10:00-12:00; Su 13:00-17:00");
|
||||
}],
|
||||
["JOIN OH with end hours", () => {
|
||||
const rules = OH.ToString(
|
||||
OH.MergeTimes([
|
||||
|
||||
{
|
||||
weekday: 1,
|
||||
endHour: 23,
|
||||
endMinutes: 30,
|
||||
startHour: 23,
|
||||
startMinutes: 0
|
||||
}, {
|
||||
weekday: 1,
|
||||
endHour: 24,
|
||||
endMinutes: 0,
|
||||
startHour: 23,
|
||||
startMinutes: 30
|
||||
},
|
||||
|
||||
]));
|
||||
equal(rules, "Tu 23:00-00:00");
|
||||
}],
|
||||
["JOIN OH with overflowed hours", () => {
|
||||
const rules = OH.ToString(
|
||||
OH.MergeTimes([
|
||||
|
||||
{
|
||||
weekday: 1,
|
||||
endHour: 23,
|
||||
endMinutes: 30,
|
||||
startHour: 23,
|
||||
startMinutes: 0
|
||||
}, {
|
||||
weekday: 1,
|
||||
endHour: 0,
|
||||
endMinutes: 0,
|
||||
startHour: 23,
|
||||
startMinutes: 30
|
||||
},
|
||||
|
||||
]));
|
||||
equal(rules, "Tu 23:00-00:00");
|
||||
}],
|
||||
["OH 24/7", () => {
|
||||
const rules = OH.Parse("24/7");
|
||||
equal(rules.length, 7);
|
||||
equal(rules[0].startHour, 0);
|
||||
const asStr = OH.ToString(rules);
|
||||
equal(asStr, "24/7");
|
||||
}],
|
||||
["OH Th[-1] off", () => {
|
||||
const rules = OH.ParseRule("Th[-1] off");
|
||||
equal(rules, null);
|
||||
}],
|
||||
["OHNo parsePH 12:00-17:00", () => {
|
||||
const rules = OH.ParseRule("PH 12:00-17:00");
|
||||
equal(rules, null);
|
||||
}],
|
||||
["OH Parse PH 12:00-17:00", () => {
|
||||
const rules = OH.ParsePHRule("PH 12:00-17:00");
|
||||
equal(rules.mode, " ");
|
||||
equal(rules.start, "12:00")
|
||||
equal(rules.end, "17:00")
|
||||
}],
|
||||
["Round", () => {
|
||||
equal(Utils.Round(15), "15.0")
|
||||
equal(Utils.Round(1), "1.0")
|
||||
equal(Utils.Round(1.5), "1.5")
|
||||
equal(Utils.Round(0.5), "0.5")
|
||||
equal(Utils.Round(1.6), "1.6")
|
||||
|
||||
equal(Utils.Round(-15), "-15.0")
|
||||
equal(Utils.Round(-1), "-1.0")
|
||||
equal(Utils.Round(-1.5), "-1.5")
|
||||
equal(Utils.Round(-0.5), "-0.5")
|
||||
equal(Utils.Round(-1.6), "-1.6")
|
||||
|
||||
}
|
||||
],
|
||||
["Regression", () => {
|
||||
|
||||
const config = {
|
||||
"#": "Bottle refill",
|
||||
"question": {
|
||||
"en": "How easy is it to fill water bottles?",
|
||||
"nl": "Hoe gemakkelijk is het om drinkbussen bij te vullen?",
|
||||
"de": "Wie einfach ist es, Wasserflaschen zu füllen?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "bottle=yes",
|
||||
"then": {
|
||||
"en": "It is easy to refill water bottles",
|
||||
"nl": "Een drinkbus bijvullen gaat makkelijk",
|
||||
"de": "Es ist einfach, Wasserflaschen nachzufüllen"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "bottle=no",
|
||||
"then": {
|
||||
"en": "Water bottles may not fit",
|
||||
"nl": "Een drinkbus past moeilijk",
|
||||
"de": "Wasserflaschen passen möglicherweise nicht"
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const tagRendering = new TagRenderingConfig(config, "test");
|
||||
equal(true, tagRendering.IsKnown({bottle: "yes"}))
|
||||
equal(false, tagRendering.IsKnown({}))
|
||||
}],
|
||||
[
|
||||
"Tag matches a lazy property",
|
||||
() => {
|
||||
const properties = {}
|
||||
const key = "_key"
|
||||
Object.defineProperty(properties, key, {
|
||||
configurable: true,
|
||||
get: function () {
|
||||
delete properties[key]
|
||||
properties[key] = "yes"
|
||||
return "yes"
|
||||
}
|
||||
})
|
||||
const filter = new Tag("_key", "yes")
|
||||
T.isTrue(filter.matchesProperties(properties), "Lazy value not matched")
|
||||
}
|
||||
],
|
||||
[
|
||||
"RegextTag matches a lazy property",
|
||||
() => {
|
||||
const properties = {}
|
||||
const key = "_key"
|
||||
Object.defineProperty(properties, key, {
|
||||
configurable: true,
|
||||
get: function () {
|
||||
delete properties[key]
|
||||
properties[key] = "yes"
|
||||
return "yes"
|
||||
}
|
||||
})
|
||||
const filter = TagUtils.Tag("_key~*")
|
||||
T.isTrue(filter.matchesProperties(properties), "Lazy value not matched")
|
||||
}
|
||||
],
|
||||
["test date comparison", () => {
|
||||
|
||||
const filter = TagUtils.Tag("date_created<2022-01-07")
|
||||
T.isFalse(filter.matchesProperties({"date_created": "2022-01-08"}), "Date comparison: expected a match")
|
||||
T.isTrue(filter.matchesProperties({"date_created": "2022-01-01"}), "Date comparison: didn't expect a match")
|
||||
|
||||
}]]);
|
||||
}
|
||||
|
||||
}
|
108
test/TestAll.ts
108
test/TestAll.ts
|
@ -1,108 +0,0 @@
|
|||
import TagSpec from "./Tag.spec";
|
||||
import ImageAttributionSpec from "./ImageAttribution.spec";
|
||||
import GeoOperationsSpec from "./GeoOperations.spec";
|
||||
import ThemeSpec from "./Theme.spec";
|
||||
import UtilsSpec from "./Utils.spec";
|
||||
import OsmObjectSpec from "./OsmObject.spec";
|
||||
import ScriptUtils from "../scripts/ScriptUtils";
|
||||
import UnitsSpec from "./Units.spec";
|
||||
import RelationSplitHandlerSpec from "./RelationSplitHandler.spec";
|
||||
import SplitActionSpec from "./SplitAction.spec";
|
||||
import {Utils} from "../Utils";
|
||||
import TileFreshnessCalculatorSpec from "./TileFreshnessCalculator.spec";
|
||||
import WikidataSpecTest from "./Wikidata.spec.test";
|
||||
import ImageProviderSpec from "./ImageProvider.spec";
|
||||
import ActorsSpec from "./Actors.spec";
|
||||
import ReplaceGeometrySpec from "./ReplaceGeometry.spec";
|
||||
import LegacyThemeLoaderSpec from "./LegacyThemeLoader.spec";
|
||||
import T from "./TestHelper";
|
||||
import CreateNoteImportLayerSpec from "./CreateNoteImportLayer.spec";
|
||||
import ValidatedTextFieldTranslationsSpec from "./ValidatedTextFieldTranslations.spec";
|
||||
import CreateCacheSpec from "./CreateCache.spec";
|
||||
import CodeQualitySpec from "./CodeQuality.spec";
|
||||
import ImportMultiPolygonSpec from "./ImportMultiPolygon.spec";
|
||||
import {ChangesetHandler} from "../Logic/Osm/ChangesetHandler";
|
||||
import ChangesetHandlerSpec from "./ChangesetHandler.spec";
|
||||
import ChangesSpec from "./Changes.spec";
|
||||
|
||||
|
||||
async function main() {
|
||||
|
||||
const allTests: T[] = [
|
||||
new ChangesSpec(),
|
||||
new ChangesetHandlerSpec(),
|
||||
new OsmObjectSpec(),
|
||||
new TagSpec(),
|
||||
new ImageAttributionSpec(),
|
||||
new GeoOperationsSpec(),
|
||||
new ThemeSpec(),
|
||||
new UtilsSpec(),
|
||||
new UnitsSpec(),
|
||||
new RelationSplitHandlerSpec(),
|
||||
new SplitActionSpec(),
|
||||
new TileFreshnessCalculatorSpec(),
|
||||
new WikidataSpecTest(),
|
||||
new ImageProviderSpec(),
|
||||
new ActorsSpec(),
|
||||
new ReplaceGeometrySpec(),
|
||||
new LegacyThemeLoaderSpec(),
|
||||
new CreateNoteImportLayerSpec(),
|
||||
new ValidatedTextFieldTranslationsSpec(),
|
||||
new CreateCacheSpec(),
|
||||
new CodeQualitySpec(),
|
||||
new ImportMultiPolygonSpec(),
|
||||
]
|
||||
ScriptUtils.fixUtils();
|
||||
const realDownloadFunc = Utils.externalDownloadFunction;
|
||||
|
||||
Utils.externalDownloadFunction = async (url) => {
|
||||
console.error("Fetching ", url, "blocked in tests, use Utils.injectJsonDownloadForTests")
|
||||
const data = await realDownloadFunc(url)
|
||||
console.log("\n\n ----------- \nBLOCKED DATA\n Utils.injectJsonDownloadForTests(\n" +
|
||||
" ", JSON.stringify(url), ", \n",
|
||||
" ", JSON.stringify(data), "\n )\n------------------\n\n")
|
||||
throw "Detected internet access for URL " + url + ", please inject it with Utils.injectJsonDownloadForTests"
|
||||
}
|
||||
|
||||
let args = [...process.argv]
|
||||
args.splice(0, 2)
|
||||
args = args.map(a => a.toLowerCase().replace(/"/g, ""))
|
||||
|
||||
const allFailures: { testsuite: string, name: string, msg: string } [] = []
|
||||
let testsToRun = allTests
|
||||
if (args.length > 0) {
|
||||
args = args.map(a => a.toLowerCase()).map(a => {
|
||||
if (!a.endsWith("spec")) {
|
||||
return a + "spec"
|
||||
} else {
|
||||
return a;
|
||||
}
|
||||
})
|
||||
testsToRun = allTests.filter(t => args.indexOf(t.name.toLowerCase()) >= 0)
|
||||
console.log("Only running test "+testsToRun.join(", "))
|
||||
}
|
||||
|
||||
if (testsToRun.length == 0) {
|
||||
const available = allTests.map(t => t.name)
|
||||
available.sort()
|
||||
throw "No tests found. Try one of " + available.join(", ")
|
||||
}
|
||||
|
||||
for (let i = 0; i < testsToRun.length; i++) {
|
||||
const test = testsToRun[i];
|
||||
console.log(" Running test", i, "/", testsToRun.length, test.name)
|
||||
|
||||
allFailures.push(...(await test.Run() ?? []))
|
||||
console.log("OK!")
|
||||
}
|
||||
if (allFailures.length > 0) {
|
||||
for (const failure of allFailures) {
|
||||
console.error(" !! " + failure.testsuite + "." + failure.name + " failed due to: " + failure.msg)
|
||||
}
|
||||
throw "Some test failed"
|
||||
}
|
||||
console.log("All tests successful: ", testsToRun.map(t => t.name).join(", "))
|
||||
|
||||
}
|
||||
|
||||
main()
|
|
@ -1,86 +0,0 @@
|
|||
export default class T {
|
||||
|
||||
public readonly name: string;
|
||||
private readonly _tests: [string, (() => (void | Promise<void>))][];
|
||||
|
||||
constructor(tests: [string, () => (Promise<void> | void)][]) {
|
||||
this.name = this.constructor.name;
|
||||
this._tests = tests;
|
||||
}
|
||||
|
||||
static assertContains(needle: string, actual: string) {
|
||||
if (actual.indexOf(needle) < 0) {
|
||||
throw `The substring ${needle} was not found`
|
||||
}
|
||||
}
|
||||
|
||||
static isTrue(b: boolean, msg: string) {
|
||||
if (!b) {
|
||||
throw "Expected true, but got false: " + msg
|
||||
}
|
||||
}
|
||||
|
||||
static equals(expected, got, msg?) {
|
||||
if (expected !== got) {
|
||||
throw "Not the same: " + (msg ?? "") + "\n" +
|
||||
"Expected: " + expected + "\n" +
|
||||
"Got : " + got
|
||||
}
|
||||
}
|
||||
|
||||
static isFalse(b: boolean, msg: string) {
|
||||
if (b) {
|
||||
throw "Expected false, but got true: " + msg
|
||||
}
|
||||
}
|
||||
|
||||
static listIdentical<T>(expected: T[], actual: T[]): void {
|
||||
if (expected === undefined) {
|
||||
throw "ListIdentical failed: expected list is undefined"
|
||||
}
|
||||
if (actual === undefined) {
|
||||
throw "ListIdentical failed: actual list is undefined"
|
||||
}
|
||||
if (expected.length !== actual.length) {
|
||||
throw `ListIdentical failed: expected a list of length ${expected.length} but got a list of length ${actual.length}`
|
||||
}
|
||||
for (let i = 0; i < expected.length; i++) {
|
||||
if (Array.isArray(expected[i])) {
|
||||
T.listIdentical(<any>expected[i], <any>actual[i])
|
||||
} else if (expected[i] !== actual[i]) {
|
||||
throw `ListIdentical failed at index ${i}: expected ${expected[i]} but got ${actual[i]}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RUns the test, returns the error messages.
|
||||
* Returns an empty list if successful
|
||||
* @constructor
|
||||
*/
|
||||
public async Run(): Promise<{ testsuite: string, name: string, msg: string } []> {
|
||||
const failures: { testsuite: string, name: string, msg: string } [] = []
|
||||
for (const [name, test] of this._tests) {
|
||||
try {
|
||||
const r = test()
|
||||
if (r instanceof Promise) {
|
||||
try {
|
||||
await r
|
||||
} catch (e) {
|
||||
console.log("ASYNC ERROR: ", e, e.stack)
|
||||
failures.push({testsuite: this.name, name: name, msg: "" + e});
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.log("ERROR: ", e, e.stack)
|
||||
failures.push({testsuite: this.name, name: name, msg: "" + e});
|
||||
}
|
||||
}
|
||||
if (failures.length == 0) {
|
||||
return undefined
|
||||
} else {
|
||||
return failures
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import * as assert from "assert";
|
||||
import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson";
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
|
||||
import * as bookcaseLayer from "../assets/generated/layers/public_bookcase.json"
|
||||
import {TagRenderingConfigJson} from "../Models/ThemeConfig/Json/TagRenderingConfigJson";
|
||||
import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson";
|
||||
import Constants from "../Models/Constants";
|
||||
import {PrepareTheme} from "../Models/ThemeConfig/Conversion/PrepareTheme";
|
||||
|
||||
export default class ThemeSpec extends T {
|
||||
constructor() {
|
||||
super([
|
||||
["Nested overrides work", () => {
|
||||
|
||||
let themeConfigJson: LayoutConfigJson = {
|
||||
description: "Descr",
|
||||
icon: "",
|
||||
layers: [
|
||||
{
|
||||
builtin: "public_bookcase",
|
||||
override: {
|
||||
source: {
|
||||
geoJson: "xyz"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
maintainer: "",
|
||||
startLat: 0,
|
||||
startLon: 0,
|
||||
startZoom: 0,
|
||||
title: {
|
||||
en: "Title"
|
||||
},
|
||||
version: "",
|
||||
id: "test"
|
||||
}
|
||||
// TOtal cheat: disable the default layers:
|
||||
Constants.added_by_default.splice(0, Constants.added_by_default.length)
|
||||
const sharedLayers = new Map<string, LayerConfigJson>()
|
||||
sharedLayers.set("public_bookcase", bookcaseLayer["default"])
|
||||
themeConfigJson = new PrepareTheme({
|
||||
tagRenderings: new Map<string, TagRenderingConfigJson>(),
|
||||
sharedLayers: sharedLayers
|
||||
}).convertStrict( themeConfigJson, "test")
|
||||
const themeConfig = new LayoutConfig(themeConfigJson);
|
||||
assert.equal("xyz", themeConfig.layers[0].source.geojsonSource)
|
||||
|
||||
|
||||
}]
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import TileFreshnessCalculator from "../Logic/FeatureSource/TileFreshnessCalculator";
|
||||
import {Tiles} from "../Models/TileRange";
|
||||
import {equal} from "assert";
|
||||
|
||||
export default class TileFreshnessCalculatorSpec extends T {
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
[
|
||||
"TileFresnessTests",
|
||||
() => {
|
||||
const calc = new TileFreshnessCalculator();
|
||||
// 19/266407/175535
|
||||
const date = new Date()
|
||||
date.setTime(42)
|
||||
calc.addTileLoad(Tiles.tile_index(19, 266406, 175534), date)
|
||||
equal(42, calc.freshnessFor(19, 266406, 175534).getTime())
|
||||
equal(42, calc.freshnessFor(20, 266406 * 2, 175534 * 2 + 1).getTime())
|
||||
equal(undefined, calc.freshnessFor(19, 266406, 175535))
|
||||
equal(undefined, calc.freshnessFor(18, 266406 / 2, 175534 / 2))
|
||||
calc.addTileLoad(Tiles.tile_index(19, 266406, 175534 + 1), date)
|
||||
calc.addTileLoad(Tiles.tile_index(19, 266406 + 1, 175534), date)
|
||||
calc.addTileLoad(Tiles.tile_index(19, 266406 + 1, 175534 + 1), date)
|
||||
equal(42, calc.freshnessFor(18, 266406 / 2, 175534 / 2).getTime())
|
||||
}
|
||||
]
|
||||
])
|
||||
}
|
||||
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import {equal} from "assert";
|
||||
import {Unit} from "../Models/Unit";
|
||||
import {Denomination} from "../Models/Denomination";
|
||||
|
||||
export default class UnitsSpec extends T {
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
["Simple canonicalize", () => {
|
||||
|
||||
const unit = new Denomination({
|
||||
canonicalDenomination: "m",
|
||||
alternativeDenomination: ["meter"],
|
||||
'default': true,
|
||||
human: {
|
||||
en: "meter"
|
||||
}
|
||||
}, "test")
|
||||
|
||||
equal(unit.canonicalValue("42m"), "42 m")
|
||||
equal(unit.canonicalValue("42"), "42 m")
|
||||
equal(unit.canonicalValue("42 m"), "42 m")
|
||||
equal(unit.canonicalValue("42 meter"), "42 m")
|
||||
|
||||
|
||||
}],
|
||||
["Advanced canonicalize and back", () => {
|
||||
|
||||
const unit = new Denomination({
|
||||
"canonicalDenomination": "MW",
|
||||
"alternativeDenomination": ["megawatts", "megawatt"],
|
||||
"human": {
|
||||
"en": " megawatts",
|
||||
"nl": " megawatt"
|
||||
},
|
||||
"default": true
|
||||
}, "test");
|
||||
|
||||
const canonical = unit.canonicalValue("5")
|
||||
equal(canonical, "5 MW")
|
||||
const units = new Unit(["key"], [unit], false)
|
||||
const [detected, detectedDenom] = units.findDenomination("5 MW")
|
||||
equal(detected, "5")
|
||||
equal(detectedDenom, unit)
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import {Utils} from "../Utils";
|
||||
import {equal} from "assert";
|
||||
import LZString from "lz-string";
|
||||
|
||||
export default class UtilsSpec extends T {
|
||||
private static readonly example = {
|
||||
"id": "bookcases",
|
||||
"maintainer": "MapComplete",
|
||||
"version": "2020-08-29",
|
||||
"language": [
|
||||
"en",
|
||||
"nl",
|
||||
"de",
|
||||
"fr"
|
||||
],
|
||||
"title": {
|
||||
"en": "Open Bookcase Map",
|
||||
"nl": "Open Boekenruilkastenkaart",
|
||||
"de": "Öffentliche Bücherschränke Karte",
|
||||
"fr": "Carte des microbibliothèques"
|
||||
},
|
||||
"description": {
|
||||
"en": "A public bookcase is a small streetside cabinet, box, old phone boot or some other objects where books are stored. Everyone can place or take a book. This map aims to collect all these bookcases. You can discover new bookcases nearby and, with a free OpenStreetMap account, quickly add your favourite bookcases.",
|
||||
"nl": "Een boekenruilkast is een kastje waar iedereen een boek kan nemen of achterlaten. Op deze kaart kan je deze boekenruilkasten terugvinden en met een gratis OpenStreetMap-account, ook boekenruilkasten toevoegen of informatie verbeteren",
|
||||
"de": "Ein öffentlicher Bücherschrank ist ein kleiner Bücherschrank am Straßenrand, ein Kasten, eine alte Telefonzelle oder andere Gegenstände, in denen Bücher aufbewahrt werden. Jeder kann ein Buch hinstellen oder mitnehmen. Diese Karte zielt darauf ab, all diese Bücherschränke zu sammeln. Sie können neue Bücherschränke in der Nähe entdecken und mit einem kostenlosen OpenStreetMap-Account schnell Ihre Lieblingsbücherschränke hinzufügen.",
|
||||
"fr": "Une microbibliothèques, également appelée boite à livre, est un élément de mobilier urbain (étagère, armoire, etc) dans lequel sont stockés des livres et autres objets en accès libre. Découvrez les boites à livres prêt de chez vous, ou ajouter en une nouvelle à l'aide de votre compte OpenStreetMap."
|
||||
},
|
||||
"icon": "./assets/themes/bookcases/bookcase.svg",
|
||||
"socialImage": null,
|
||||
"startLat": 0,
|
||||
"startLon": 0,
|
||||
"startZoom": 1,
|
||||
"widenFactor": 0.05,
|
||||
"roamingRenderings": [],
|
||||
"layers": [
|
||||
"public_bookcase"
|
||||
]
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super([
|
||||
["Sort object keys", () => {
|
||||
const o = {
|
||||
x: 'x',
|
||||
abc: {'x': 'x', 'a': 'a'},
|
||||
def: 'def'
|
||||
}
|
||||
equal('{"x":"x","abc":{"x":"x","a":"a"},"def":"def"}', JSON.stringify(o))
|
||||
const copy = Utils.sortKeys(o)
|
||||
equal('{"abc":{"a":"a","x":"x"},"def":"def","x":"x"}', JSON.stringify(copy))
|
||||
}],
|
||||
|
||||
["Minify-json", () => {
|
||||
const str = JSON.stringify({title: "abc", "and": "xyz", "render": "somevalue"}, null, 0);
|
||||
const minified = Utils.MinifyJSON(str);
|
||||
console.log(minified)
|
||||
console.log("Minified version has ", minified.length, "chars")
|
||||
const restored = Utils.UnMinify(minified)
|
||||
console.log(restored)
|
||||
console.log("Restored version has ", restored.length, "chars")
|
||||
equal(str, restored)
|
||||
|
||||
}],
|
||||
["Minify-json of the bookcases", () => {
|
||||
const str = JSON.stringify(UtilsSpec.example, null, 0)
|
||||
const minified = Utils.MinifyJSON(str);
|
||||
console.log("Minified version has ", minified.length, "chars")
|
||||
const restored = Utils.UnMinify(minified)
|
||||
console.log("Restored version has ", restored.length, "chars")
|
||||
equal(str, restored)
|
||||
|
||||
}],
|
||||
["Minify-json with LZ-string of the bookcases", () => {
|
||||
const str = JSON.stringify(UtilsSpec.example, null, 0)
|
||||
const minified = LZString.compressToBase64(Utils.MinifyJSON(str));
|
||||
console.log("Minified version has ", minified.length, "chars")
|
||||
const restored = Utils.UnMinify(LZString.decompressFromBase64(minified))
|
||||
console.log("Restored version has ", restored.length, "chars")
|
||||
equal(str, restored)
|
||||
|
||||
}],
|
||||
["Minify-json with only LZ-string of the bookcases", () => {
|
||||
const str = JSON.stringify(UtilsSpec.example, null, 0)
|
||||
const minified = LZString.compressToBase64(str);
|
||||
console.log("Minified version has ", minified.length, "chars")
|
||||
const restored = LZString.decompressFromBase64(minified)
|
||||
console.log("Restored version has ", restored.length, "chars")
|
||||
equal(str, restored)
|
||||
|
||||
}],
|
||||
["TestMerge", () => {
|
||||
|
||||
const source = {
|
||||
abc: "def",
|
||||
foo: "bar",
|
||||
list0: ["overwritten"],
|
||||
"list1+": ["appended"]
|
||||
}
|
||||
const target = {
|
||||
"xyz": "omega",
|
||||
"list0": ["should-be-gone"],
|
||||
"list1": ["should-be-kept"],
|
||||
"list2": ["should-be-untouched"]
|
||||
}
|
||||
const result = Utils.Merge(source, target)
|
||||
|
||||
equal(result.abc, "def")
|
||||
equal(result.foo, "bar")
|
||||
equal(result.xyz, "omega")
|
||||
equal(result.list0.length, 1)
|
||||
equal(result.list0[0], "overwritten")
|
||||
equal(result.list1.length, 2)
|
||||
equal(result.list1[0], "should-be-kept")
|
||||
equal(result.list1[1], "appended")
|
||||
equal(result.list2.length, 1)
|
||||
equal(result.list2[0], "should-be-untouched")
|
||||
}],
|
||||
["Test merge with null", () => {
|
||||
const obj = {
|
||||
someValue: 42
|
||||
}
|
||||
const override = {
|
||||
someValue: null
|
||||
}
|
||||
Utils.Merge(override, obj)
|
||||
equal(obj.someValue, null)
|
||||
}]
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import ValidatedTextField from "../UI/Input/ValidatedTextField";
|
||||
import Translations from "../UI/i18n/Translations";
|
||||
|
||||
export default class ValidatedTextFieldTranslationsSpec extends T {
|
||||
constructor() {
|
||||
super([
|
||||
["Test all", () => {
|
||||
const ts = Translations.t.validation;
|
||||
console.log("Hello world!")
|
||||
const allErrors = Array.from(ValidatedTextField.allTypes.keys()).map(key => {
|
||||
const errors = []
|
||||
const t = ts[key]
|
||||
if (t === undefined) {
|
||||
errors.push("No tranlations at all for " + key)
|
||||
}
|
||||
return errors;
|
||||
})
|
||||
const errs = [].concat(...allErrors)
|
||||
if (errs.length > 0) {
|
||||
errs.forEach(e => console.log(e))
|
||||
// throw errs.join("\n")
|
||||
}
|
||||
}]
|
||||
]);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue