Rename tests to test; add a few tests

This commit is contained in:
Pieter Vander Vennet 2022-04-06 03:06:28 +02:00
parent df706d2f97
commit c3859d56c6
28 changed files with 33 additions and 5 deletions

17
test/Chai.spec.ts Normal file
View file

@ -0,0 +1,17 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import {Utils} from "../Utils";
describe("TestSuite", () => {
describe("function under test", () => {
it("should work", () => {
expect("abc").eq("abc")
})
})
})
it("global test", async() => {
expect("abc").eq("abc")
expect(() => {throw "hi"}).throws(/hi/)
})

45
test/CodeQuality.spec.ts Normal file
View file

@ -0,0 +1,45 @@
import {describe} from 'mocha'
import {exec} from "child_process";
/**
*
* @param forbidden: a GREP-regex. This means that '.' is a wildcard and should be escaped to match a literal dot
* @param reason
* @private
*/
function 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}`
}
}))
}
describe("Code quality", () => {
it("should not contain reverse", () => {
detectInCode("reverse()", "Reverse is stateful and changes the source list. This often causes subtle bugs")
})
it("should not contain 'constructor.name'", () => {
detectInCode("constructor\\.name", "This is not allowed, as minification does erase names.")
})
})

View file

@ -0,0 +1,126 @@
import {expect} from 'chai'
import {Utils} from "../../../Utils";
import UserRelatedState from "../../../Logic/State/UserRelatedState";
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig";
import SelectedElementTagsUpdater from "../../../Logic/Actors/SelectedElementTagsUpdater";
import * as bookcaseJson from "../../../assets/generated/themes/bookcases.json"
import {UIEventSource} from "../../../Logic/UIEventSource";
import Loc from "../../../Models/Loc";
import SelectedFeatureHandler from "../../../Logic/Actors/SelectedFeatureHandler";
import {ElementStorage} from "../../../Logic/ElementStorage";
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
}]
}
)
it("should download the 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
expect(feature.properties.name).deep.equal("Stubbekwartier-buurtbibliotheek")
// The fixme should be removed
expect(feature.properties.fixme).deep.equal(undefined)
})
it("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(_ => {
expect(selected.data.properties.id).deep.equal("node/5568693115")
expect(loc.data.zoom).deep.equal(14)
expect(loc.data.lat).deep.equal(51.2179199)
})
new SelectedFeatureHandler(hash, {
selectedElement: selected,
allElements: new ElementStorage(),
featurePipeline: undefined,
locationControl: loc,
layoutToUse: undefined
})
})

View file

@ -0,0 +1,209 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import CreateMultiPolygonWithPointReuseAction from "../../../Logic/Osm/Actions/CreateMultiPolygonWithPointReuseAction";
import {Tag} from "../../../Logic/Tags/Tag";
import {Changes} from "../../../Logic/Osm/Changes";
describe("CreateMultiPolygonWithPointReuseAction", () => {
it("should produce a 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())
const ways= descriptions.filter(d => d.type === "way")
expect(ways[0].id == -18, "unexpected id").true
expect(ways[1].id == -27, "unexpected id").true
const outer = ways[0].changes["coordinates"]
expect(outer).deep.equal(feature.geometry.coordinates[0])
const inner = ways[1].changes["coordinates"]
expect(inner).deep.equal(feature.geometry.coordinates[1])
const members = <{type: string, role: string, ref: number}[]> descriptions.find(d => d.type === "relation").changes["members"]
expect(members[0].role, "incorrect role").eq("outer")
expect(members[1].role, "incorrect role").eq("inner")
expect(members[0].type , "incorrect type").eq("way")
expect(members[1].type , "incorrect type").eq("way")
expect(members[0].ref, "incorrect id").eq(-18)
expect(members[1].ref , "incorrect id").eq(-27)
}
})
})

View file

@ -0,0 +1,25 @@
import {describe} from 'mocha'
import TileFreshnessCalculator from "../../../Logic/FeatureSource/TileFreshnessCalculator";
import {Tiles} from "../../../Models/TileRange";
import {expect} from "chai"
describe("TileFreshnessCalculator", () => {
it("should get the freshness for loaded tiles",
() => {
const calc = new TileFreshnessCalculator();
// 19/266407/175535
const date = new Date()
date.setTime(42)
calc.addTileLoad(Tiles.tile_index(19, 266406, 175534), date)
expect(calc.freshnessFor(19, 266406, 175534).getTime()).eq(42)
expect(calc.freshnessFor(20, 266406 * 2, 175534 * 2 + 1).getTime()).eq(42)
expect(calc.freshnessFor(19, 266406, 175535)).undefined
expect(calc.freshnessFor(18, 266406 / 2, 175534 / 2)).undefined
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)
expect(calc.freshnessFor(18, 266406 / 2, 175534 / 2).getTime()).eq(42)
})
})

View file

@ -0,0 +1,186 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import * as turf from "@turf/turf";
import {GeoOperations} from "../../Logic/GeoOperations";
describe("GeoOperations", () => {
describe("calculateOverlap", () => {
it("should not give too much overlap (regression test)", () => {
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)
expect(p0).not.null
const p1 = turf.polygon(polyHouse.geometry.coordinates)
expect(p1).not.null
const overlaps = GeoOperations.calculateOverlap(polyGrb, [polyHouse])
expect(overlaps).empty
const overlapsRev = GeoOperations.calculateOverlap(polyHouse, [polyGrb])
expect(overlapsRev).empty
})
})
})

View file

@ -0,0 +1,77 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import AllImageProviders from "../../../Logic/ImageProviders/AllImageProviders";
import {UIEventSource} from "../../../Logic/UIEventSource";
import {Utils} from "../../../Utils";
describe("ImageProviders", () => {
it("should work on a variaty of inputs", () => {
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"
}
expect(img.url).deep.equal(url)
if (providerName) {
expect(providerName).deep.equal(img.provider.constructor.name)
}
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"
})
})
})

View file

@ -0,0 +1,690 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import {Utils} from "../../../../Utils";
import {OsmObject, OsmRelation} from "../../../../Logic/Osm/OsmObject";
import {InPlaceReplacedmentRTSH, TurnRestrictionRSH} from "../../../../Logic/Osm/Actions/RelationSplitHandler";
import {Changes} from "../../../../Logic/Osm/Changes";
describe("RelationSplitHandler", () => {
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"
}
}]
}
)
it("should split all cycling relation (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"
expect(allIds.indexOf(expected) >= 0, "didn't find the expected order of ids in the relation to test").true
})
it(
"should split turn restrictions (split of https://www.openstreetmap.org/way/143298912)",
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"
expect(allIds).deep.equal(expected)
// 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())
expect(changesReverse.length).deep.equal(0)
}
)
})

View file

@ -0,0 +1,927 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import Minimap from "../../../../UI/Base/Minimap";
import {Utils} from "../../../../Utils";
import LayoutConfig from "../../../../Models/ThemeConfig/LayoutConfig";
import State from "../../../../State";
import {BBox} from "../../../../Logic/BBox";
import ReplaceGeometryAction from "../../../../Logic/Osm/Actions/ReplaceGeometryAction";
describe("ReplaceGeometryAction", () => {
const 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"
]
}
]
}
]
}
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")
it("should move nodes accordingly", async () => {
const layout = new LayoutConfig(<any>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()
expect(closestIds.closestIds).deep.equal([9219979643,
1728823481,
4978289383,
4978289388,
9219979646,
9219979647,
4978288381,
4978289386,
4978289384,
1728823514,
undefined])
expect(closestIds.reprojectedNodes.size).deep.equal(1)
const reproj = closestIds.reprojectedNodes.get(1728823549)
expect(reproj.projectAfterIndex).deep.equal(1)
expect(reproj.newLon).deep.equal(3.2168880864669203)
expect(reproj.newLat).deep.equal(51.214739524104694)
expect(closestIds.detachedNodes.size).deep.equal(0)
const changes = await action.Perform(state.changes)
expect(changes[11].changes["coordinates"]).deep.equal([[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]])
})
})

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
import {expect} from 'chai'
import {ChangeDescription} from "../../../Logic/Osm/Actions/ChangeDescription";
import {Changes} from "../../../Logic/Osm/Changes";
it("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,
[]
)
expect(descr.modifiedObjects).length(0)
expect(descr.deletedObjects).length(0)
expect(descr.newObjects).length(1)
const ch = descr.newObjects[0]
expect(ch.tags["foo"]).eq("bar")
expect(ch.tags["someKey"]).eq("someValue")
})

View file

@ -0,0 +1,195 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import {Utils} from "../../../Utils";
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";
describe("ChangesetHanlder", () => {
describe("RewriteTagsOf", () => {
it("should insert new tags", () => {
const changesetHandler = 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",
}
}
const rewritten = changesetHandler.RewriteTagsOf(
[{
key: "newTag",
value: "newValue",
aggregate: false
}],
new Map<string, string>(),
oldChangesetMeta)
const d = Utils.asDict(rewritten)
expect(d.size).deep.equal(10)
expect(d.get("answer")).deep.equal("5")
expect(d.get("comment")).deep.equal("Adding data with #MapComplete for theme #toerisme_vlaanderen")
expect(d.get("created_by")).deep.equal("MapComplete 0.16.6")
expect(d.get("host")).deep.equal("https://mapcomplete.osm.be/toerisme_vlaanderen.html")
expect(d.get("imagery")).deep.equal("osm")
expect(d.get("source")).deep.equal("survey")
expect(d.get("source:node/-1")).deep.equal("note/1234")
expect(d.get("theme")).deep.equal("toerisme_vlaanderen")
expect(d.get("newTag")).deep.equal("newValue")
})
it("should aggregate numeric tags", () => {
const changesetHandler = 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",
}
}
const rewritten = changesetHandler.RewriteTagsOf(
[{
key: "answer",
value: "37",
aggregate: true
}],
new Map<string, string>(),
oldChangesetMeta)
const d = Utils.asDict(rewritten)
expect(d.size).deep.equal(9)
expect(d.get("answer")).deep.equal("42")
expect(d.get("comment")).deep.equal("Adding data with #MapComplete for theme #toerisme_vlaanderen")
expect(d.get("created_by")).deep.equal("MapComplete 0.16.6")
expect(d.get("host")).deep.equal("https://mapcomplete.osm.be/toerisme_vlaanderen.html")
expect(d.get("imagery")).deep.equal("osm")
expect(d.get("source")).deep.equal("survey")
expect(d.get("source:node/-1")).deep.equal("note/1234")
expect(d.get("theme")).deep.equal("toerisme_vlaanderen")
})
it("should rewrite special reasons with the correct ID", () => {
const changesetHandler = 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",
}
}
const rewritten = changesetHandler.RewriteTagsOf(
[],
new Map<string, string>([["node/-1", "node/42"]]),
oldChangesetMeta)
const d = Utils.asDict(rewritten)
expect(d.size).deep.equal(9)
expect(d.get("answer")).deep.equal("5")
expect(d.get("comment")).deep.equal("Adding data with #MapComplete for theme #toerisme_vlaanderen")
expect(d.get("created_by")).deep.equal("MapComplete 0.16.6")
expect(d.get("host")).deep.equal("https://mapcomplete.osm.be/toerisme_vlaanderen.html")
expect(d.get("imagery")).deep.equal("osm")
expect(d.get("source")).deep.equal("survey")
expect(d.get("source:node/42")).deep.equal("note/1234")
expect(d.get("theme")).deep.equal("toerisme_vlaanderen")
})
})
describe("rewriteMetaTags" , () => {
it("should rewrite special reasons with the correct ID", () => {
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)
expect(hasSpecialMotivationChanges, "Special rewrite did not trigger").true
// Rewritten inline by rewriteMetaTags
expect(extraMetaTags[1].key).deep.equal("source:node/42")
expect(extraMetaTags[1].value).deep.equal("note/1234")
expect(extraMetaTags[0].key).deep.equal("created_by")
expect(extraMetaTags[0].value).deep.equal("mapcomplete")
})
})
})

View file

@ -0,0 +1,23 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import {OsmObject} from "../../../Logic/Osm/OsmObject";
import {Utils} from "../../../Utils";
describe("OsmObject", () => {
describe("download referencing ways", () => {
Utils.injectJsonDownloadForTests(
"https://www.openstreetmap.org/api/0.6/node/1124134958/ways", {"version":"0.6","generator":"CGImap 0.8.6 (49805 spike-06.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"}}]})
it("should download referencing ways",
async () => {
const ways = await OsmObject.DownloadReferencingWays("node/1124134958")
expect(ways).not.undefined
expect(ways).length(4)
})
})
})

View file

@ -0,0 +1,40 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import {TagUtils} from "../../../Logic/Tags/TagUtils";
import {Tag} from "../../../Logic/Tags/Tag";
describe("Lazy object properties", () => {
it("should be matche by a normal tag", () => {
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")
expect(filter.matchesProperties(properties)).true
})
it("should be matched by a RegexTag", () => {
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~*")
expect(filter.matchesProperties(properties)).true;
})
})

View file

@ -0,0 +1,150 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import {TagsFilter} from "../../../Logic/Tags/TagsFilter";
import {And} from "../../../Logic/Tags/And";
import {Tag} from "../../../Logic/Tags/Tag";
import {TagUtils} from "../../../Logic/Tags/TagUtils";
import {Or} from "../../../Logic/Tags/Or";
import {RegexTag} from "../../../Logic/Tags/RegexTag";
describe("Tag optimalization", () => {
describe("And", () => {
it("with condition and nested and should be flattened", () => {
const t = new And(
[
new And([
new Tag("x", "y")
]),
new Tag("a", "b")
]
)
const opt =<TagsFilter> t.optimize()
expect(TagUtils.toString(opt)).eq(`a=b&x=y`)
})
it("with nested ors and commons property should be extracted", () => {
// foo&bar & (x=y | a=b) & (x=y | c=d) & foo=bar is equivalent too foo=bar & ((x=y) | (a=b & c=d))
const 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")
])
])
const opt =<TagsFilter> t.optimize()
expect(TagUtils.toString(opt)).eq("foo=bar& (x=y| (a=b&c=d) )")
})
it("should move regextag to the end", () => {
const t = new And([
new RegexTag("x","y"),
new Tag("a","b")
])
const opt =<TagsFilter> t.optimize()
expect(TagUtils.toString(opt)).eq("a=b&x~^y$")
})
it("should sort tags by their popularity (least popular first)", () => {
const t = new And([
new Tag("bicycle","yes"),
new Tag("amenity","binoculars")
])
const opt =<TagsFilter> t.optimize()
expect(TagUtils.toString(opt)).eq("amenity=binoculars&bicycle=yes")
})
it("should optimize an advanced, real world case", () => {
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"
]
}
]});
const opt = <TagsFilter> filter.optimize()
const expected = "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$)"
expect(TagUtils.toString(opt).replace(/ /g, ""))
.eq(expected.replace(/ /g, ""))
})
})
describe("Or", () => {
it("with nested And which has a common property should be dropped", () => {
const t = new Or([
new Tag("foo","bar"),
new And([
new Tag("foo", "bar"),
new Tag("x", "y"),
])
])
const opt =<TagsFilter> t.optimize()
expect(TagUtils.toString(opt)).eq("foo=bar")
})
})
})

View file

@ -0,0 +1,52 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import {TagUtils} from "../../../Logic/Tags/TagUtils";
import {equal} from "assert";
describe("TagUtils", () => {
describe("ParseTag", () => {
it("should refuse a key!=* tag", () => {
expect(() => TagUtils.Tag("key!=*")).to.throw();
})
it("should handle compare tag <=5", () => {
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);
})
it("should handle compare tag < 5", () => {
const 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);
})
it("should handle compare tag >5", () => {
const 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);
})
it("should handle compare tag >=5", () => {
const 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);
})
it("should handle date comparison tags", () => {
const filter = TagUtils.Tag("date_created<2022-01-07")
expect(filter.matchesProperties({"date_created": "2022-01-08"})).false
expect(filter.matchesProperties({"date_created": "2022-01-01"})).true
})
})
})

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,32 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import {Utils} from "../../../../Utils";
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 * as bookcases from "../../../../assets/layers/public_bookcase/public_bookcase.json";
import CreateNoteImportLayer from "../../../../Models/ThemeConfig/Conversion/CreateNoteImportLayer";
describe("CreateNoteImportLayer", () => {
it("should generate a layerconfig", () => {
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")
expect(generatedLayer.isShown.mappings[1].if["and"][1].or[0].and[0]).deep.equal("_tags~(^|.*;)amenity=public_bookcase($|;.*)")
expect(generatedLayer.minzoom <= layer.minzoom, "Zoomlevel is to high").true
let renderings = Utils.NoNull(Utils.NoNull(generatedLayer.tagRenderings
.map(tr => (<TagRenderingConfigJson>tr).render))
.map(render => render["en"]))
expect(renderings.some(r => r.indexOf("import_button") > 0), "no import button found").true
})
})

View file

@ -0,0 +1,153 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import LayoutConfig from "../../../../Models/ThemeConfig/LayoutConfig";
import {FixLegacyTheme} from "../../../../Models/ThemeConfig/Conversion/LegacyJsonConvert";
describe("FixLegacyTheme", () => {
it("should create a working theme config", () => {
const 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"
]
}
]
}
const fixed = new FixLegacyTheme().convert(
<any> walking_node_theme,
"While testing")
expect(fixed.errors, "Could not fix the legacy theme").empty
const theme = new LayoutConfig(fixed.result, false,"test")
expect(theme).not.undefined
})
})

View file

@ -0,0 +1,130 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import {LayerConfigJson} from "../../../../Models/ThemeConfig/Json/LayerConfigJson";
import {TagRenderingConfigJson} from "../../../../Models/ThemeConfig/Json/TagRenderingConfigJson";
import LineRenderingConfigJson from "../../../../Models/ThemeConfig/Json/LineRenderingConfigJson";
import {ExpandRewrite, PrepareLayer, RewriteSpecial} from "../../../../Models/ThemeConfig/Conversion/PrepareLayer";
import {
QuestionableTagRenderingConfigJson
} from "../../../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson";
import RewritableConfigJson from "../../../../Models/ThemeConfig/Json/RewritableConfigJson";
describe("ExpandRewrite", () => {
it("should not allow overlapping keys", () => {
const spec = <RewritableConfigJson<string>>{
rewrite: {
sourceString: ["xyz", "longer_xyz"],
into: [["a", "b"], ["A, B"]],
},
renderings: "The value of xyz is longer_xyz"
}
const rewrite = new ExpandRewrite()
expect(() => rewrite.convert(spec, "test")).to.throw
})
})
describe("PrepareLayer", () => {
it("should expand rewrites in map renderings", () => {
const exampleLayer: LayerConfigJson = {
id: "testlayer",
source: {
osmTags: "key=value"
},
mapRendering: [
{
"rewrite": {
sourceString: ["left|right", "lr_offset"],
into: [
["left", -6],
[ "right", +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"}]
}
expect(result).deep.eq(expected)
})
})
describe('RewriteSpecial', function () {
it("should rewrite the UK import button", () => {
const tr = <QuestionableTagRenderingConfigJson>{
"id": "uk_addresses_import_button",
"render": {
"special": {
"type": "import_button",
"targetLayer": "address",
"tags": "urpn_count=$urpn_count;ref:GB:uprn=$ref:GB:uprn$",
"text": "Add this address",
"icon": "./assets/themes/uk_addresses/housenumber_add.svg",
"location_picker": "none"
}
}
}
const r = new RewriteSpecial().convert(tr, "test").result
expect(r).to.deep.eq({
"id": "uk_addresses_import_button",
"render": {'*': "{import_button(address,urpn_count=$urpn_count;ref:GB:uprn=$ref:GB:uprn$,Add this address,./assets/themes/uk_addresses/housenumber_add.svg,,,,none)}"}
})
})
});

View file

@ -0,0 +1,106 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import {LayoutConfigJson} from "../../../../Models/ThemeConfig/Json/LayoutConfigJson";
import {LayerConfigJson} from "../../../../Models/ThemeConfig/Json/LayerConfigJson";
import {PrepareTheme} from "../../../../Models/ThemeConfig/Conversion/PrepareTheme";
import {TagRenderingConfigJson} from "../../../../Models/ThemeConfig/Json/TagRenderingConfigJson";
import LayoutConfig from "../../../../Models/ThemeConfig/LayoutConfig";
import * as bookcaseLayer from "../../../../assets/generated/layers/public_bookcase.json"
import LayerConfig from "../../../../Models/ThemeConfig/LayerConfig";
import {ExtractImages} from "../../../../Models/ThemeConfig/Conversion/FixImages";
import * as cyclofix from "../../../../assets/generated/themes/cyclofix.json"
import {Tag} from "../../../../Logic/Tags/Tag";
const 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"
}
describe("PrepareTheme", () => {
it("should substitute layers", () => {
const sharedLayers = new Map<string, LayerConfigJson>()
sharedLayers.set("public_bookcase", bookcaseLayer["default"])
const theme ={...themeConfigJson, layers: ["public_bookcase"]}
const prepareStep = new PrepareTheme({
tagRenderings: new Map<string, TagRenderingConfigJson>(),
sharedLayers: sharedLayers
})
let themeConfigJsonPrepared = prepareStep.convert(theme, "test").result
const themeConfig = new LayoutConfig(themeConfigJsonPrepared);
const layerUnderTest = <LayerConfig> themeConfig.layers.find(l => l.id === "public_bookcase")
expect(layerUnderTest.source.osmTags).deep.eq(new Tag("amenity","public_bookcase"))
})
it("should apply override", () => {
const sharedLayers = new Map<string, LayerConfigJson>()
sharedLayers.set("public_bookcase", bookcaseLayer["default"])
let themeConfigJsonPrepared = new PrepareTheme({
tagRenderings: new Map<string, TagRenderingConfigJson>(),
sharedLayers: sharedLayers
}).convert( themeConfigJson, "test").result
const themeConfig = new LayoutConfig(themeConfigJsonPrepared);
const layerUnderTest = <LayerConfig> themeConfig.layers.find(l => l.id === "public_bookcase")
expect(layerUnderTest.source.geojsonSource).eq("xyz")
})
it("should apply override", () => {
const sharedLayers = new Map<string, LayerConfigJson>()
sharedLayers.set("public_bookcase", bookcaseLayer["default"])
let themeConfigJsonPrepared = new PrepareTheme({
tagRenderings: new Map<string, TagRenderingConfigJson>(),
sharedLayers: sharedLayers
}).convert({...themeConfigJson, overrideAll: {source: {geoJson: "https://example.com/data.geojson"}}}, "test").result
const themeConfig = new LayoutConfig(themeConfigJsonPrepared);
const layerUnderTest = <LayerConfig> themeConfig.layers.find(l => l.id === "public_bookcase")
expect(layerUnderTest.source.geojsonSource).eq("https://example.com/data.geojson")
})
})
describe("ExtractImages", () => {
it("should find all images in a themefile", () => {
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) {
expect(images).contains(expected)
}
})
})

View file

@ -0,0 +1,71 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import TagRenderingConfig from "../../../Models/ThemeConfig/TagRenderingConfig";
import Locale from "../../../UI/i18n/Locale";
describe("TagRenderingConfig", () => {
describe("isKnown", () => {
it("should give correct render values", () => {
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");
expect(tr.GetRenderValue({"foo": "bar"})).undefined
expect (tr.GetRenderValue({"noname": "yes"})?.textFor("nl")).eq("Has no name")
expect( tr.GetRenderValue({"name": "xyz"})?.textFor("nl")).eq("Ook een {name}")
expect( tr.GetRenderValue({"foo": "bar"})).undefined
})
it("should give a correct indication", () => {
// tests a regression in parsing
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");
expect(tagRendering.IsKnown({bottle: "yes"})).true
expect(tagRendering.IsKnown({})).false
})
})
})

30
test/Models/Units.spec.ts Normal file
View file

@ -0,0 +1,30 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import {Unit} from "../../Models/Unit";
import {Denomination} from "../../Models/Denomination";
describe("Unit", () => {
it("should convert a value back and forth", () => {
const unit = new Denomination({
"canonicalDenomination": "MW",
"alternativeDenomination": ["megawatts", "megawatt"],
"human": {
"en": " megawatts",
"nl": " megawatt"
},
"default": true
}, "test");
const canonical = unit.canonicalValue("5")
expect(canonical).eq( "5 MW")
const units = new Unit(["key"], [unit], false)
const [detected, detectedDenom] = units.findDenomination("5 MW")
expect(detected).eq( "5")
expect(detectedDenom).eq( unit)
}
)
})

View file

@ -0,0 +1,19 @@
import {describe} from 'mocha'
import SpecialVisualizations from "../../UI/SpecialVisualizations";
import {expect} from "chai";
describe("SpecialVisualisations", () => {
describe("predifined special visualisations", () => {
it("should not have an argument called 'type'", () => {
const specials = SpecialVisualizations.specialVisualizations
for (const special of specials) {
expect(special.funcName).not.eq('type', "A special visualisation is not allowed to be named 'type', as this will conflict with the 'special'-blocks")
for (const arg of special.args) {
expect(arg.name).not.eq('type', "An argument is not allowed to be called 'type', as this will conflict with the 'special'-blocks")
}
}
})
})
})

View file

@ -0,0 +1,14 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import Translations from "../../UI/i18n/Translations";
import ValidatedTextField from "../../UI/Input/ValidatedTextField";
describe("ValidatedTextFields", () => {
it("should all have description in the translations", () => {
const ts = Translations.t.validation;
const missingTranslations = Array.from(ValidatedTextField.allTypes.keys())
.filter(key => ts[key] === undefined || ts[key].description === undefined)
expect(missingTranslations, "These validated text fields don't have a type name defined in en.json. (Did you just add one? Run `npm run generate:translations`)").to.be.empty
})
})

View file

@ -0,0 +1,75 @@
import {Utils} from "../Utils";
import LZString from "lz-string";
import {describe} from 'mocha'
import {expect} from 'chai'
const 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"
]
}
describe("Utils", () => {
describe("Minify-json", () => {
it("should work in two directions", () => {
const str = JSON.stringify({title: "abc", "and": "xyz", "render": "somevalue"});
const minified = Utils.MinifyJSON(str);
const restored = Utils.UnMinify(minified)
expect(str).eq(restored)
})
it("should minify and restore the bookcase example", () => {
const str = JSON.stringify(example, null, 0)
const minified = Utils.MinifyJSON(str);
const restored = Utils.UnMinify(minified)
expect(str).eq(restored)
})
it("should LZ-compress a theme", () => {
const str = JSON.stringify(example, null, 0)
const minified = LZString.compressToBase64(Utils.MinifyJSON(str));
const restored = Utils.UnMinify(LZString.decompressFromBase64(minified))
expect(str).eq(restored)
})
it("shoud be able to decode the LZ-compression of a theme", () => {
const str = JSON.stringify(example, null, 0)
const minified = LZString.compressToBase64(str);
const restored = LZString.decompressFromBase64(minified)
expect(str).eq(restored)
})
})
})

File diff suppressed because one or more lines are too long

24
test/testhooks.ts Normal file
View file

@ -0,0 +1,24 @@
import ScriptUtils from "../scripts/ScriptUtils";
import {Utils} from "../Utils";
export const mochaHooks = {
beforeEach(done) {
ScriptUtils.fixUtils();
// Block internet access
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 new Error("Detected internet access for URL " + url + ", please inject it with Utils.injectJsonDownloadForTests")
}
done();
}
}