2021-11-14 16:57:14 +01:00
import T from "./TestHelper" ;
2022-02-09 22:37:21 +01:00
import { FixLegacyTheme } from "../Models/ThemeConfig/Conversion/LegacyJsonConvert" ;
2021-11-14 16:57:14 +01:00
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig" ;
2021-12-21 18:35:31 +01:00
import { TagRenderingConfigJson } from "../Models/ThemeConfig/Json/TagRenderingConfigJson" ;
2022-01-21 02:27:31 +01:00
import { AddMiniMap } from "../Models/ThemeConfig/Conversion/PrepareTheme" ;
2022-02-17 23:55:01 +01:00
import { DetectMappingsWithImages , DetectShadowedMappings } from "../Models/ThemeConfig/Conversion/Validation" ;
2022-02-04 15:48:26 +01:00
import * as Assert from "assert" ;
2022-02-18 23:10:27 +01:00
import { ExtractImages , FixImages } from "../Models/ThemeConfig/Conversion/FixImages" ;
2022-02-28 18:52:28 +01:00
import { PrepareLayer } from "../Models/ThemeConfig/Conversion/PrepareLayer" ;
import { LayerConfigJson } from "../Models/ThemeConfig/Json/LayerConfigJson" ;
import LineRenderingConfigJson from "../Models/ThemeConfig/Json/LineRenderingConfigJson" ;
2021-11-14 16:57:14 +01:00
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"
] ,
2022-01-18 20:18:12 +01:00
socialImage : "img.jpg" ,
2021-11-14 16:57:14 +01:00
"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"
]
}
]
}
2022-02-18 23:10:27 +01:00
private static readonly verkeerde_borden = {
2022-02-04 15:48:26 +01:00
"id" : "https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/VerkeerdeBordenDatabank.json" ,
2022-01-31 00:39:54 +01:00
"title" : {
2022-02-04 15:48:26 +01:00
"nl" : "VerkeerdeBordenDatabank" ,
"en" : "Erratic Signs Database"
2022-01-31 00:39:54 +01:00
} ,
2022-02-04 15:48:26 +01:00
"maintainer" : "Seppe Santens" ,
"icon" : "https://upload.wikimedia.org/wikipedia/commons/b/bc/Belgian_traffic_sign_A51.svg" ,
2022-01-31 00:39:54 +01:00
"description" : {
2022-02-04 15:48:26 +01:00
"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
2022-01-31 00:39:54 +01:00
} ,
"layers" : [
{
2022-02-04 15:48:26 +01:00
"id" : "trafficsign" ,
2022-01-31 00:39:54 +01:00
"name" : {
2022-02-04 15:48:26 +01:00
"nl" : "verkeersbord" ,
"en" : "traffic sign"
2022-01-31 00:39:54 +01:00
} ,
2022-02-04 15:48:26 +01:00
"source" : {
"osmTags" : {
"and" : [
"traffic_sign~*" ,
"traffic_sign:issue~*"
]
}
} ,
"minzoom" : 10 ,
2022-01-31 00:39:54 +01:00
"title" : {
"render" : {
2022-02-04 15:48:26 +01:00
"nl" : "verkeersbord" ,
"en" : "traffic sign"
}
2022-01-31 00:39:54 +01:00
} ,
"tagRenderings" : [
"images" ,
{
2022-02-04 15:48:26 +01:00
"render" : {
"nl" : "ID verkeersbord: {traffic_sign}" ,
"en" : "traffic sign ID: {traffic_sign}"
2022-01-31 00:39:54 +01:00
} ,
"question" : {
2022-02-04 15:48:26 +01:00
"nl" : "Wat is het ID voor dit verkeersbord?" ,
"en" : "What is ID for this traffic sign?"
2022-01-31 00:39:54 +01:00
} ,
2022-02-04 15:48:26 +01:00
"freeform" : {
"key" : "traffic_sign"
2022-01-31 00:39:54 +01:00
} ,
2022-02-04 15:48:26 +01:00
"id" : "trafficsign-traffic_sign"
2022-01-31 00:39:54 +01:00
} ,
{
2022-02-04 15:48:26 +01:00
"render" : {
"nl" : "Probleem bij dit verkeersbord: {traffic_sign:issue}" ,
"en" : "Issue with this traffic sign: {traffic_sign:issue}"
} ,
2022-01-31 00:39:54 +01:00
"question" : {
2022-02-04 15:48:26 +01:00
"nl" : "Wat is het probleem met dit verkeersbord?" ,
"en" : "What is the issue with this traffic sign?"
2022-01-31 00:39:54 +01:00
} ,
"freeform" : {
2022-02-04 15:48:26 +01:00
"key" : "traffic_sign:issue"
2022-01-31 00:39:54 +01:00
} ,
2022-02-04 15:48:26 +01:00
"id" : "trafficsign-traffic_sign:issue"
2022-01-31 00:39:54 +01:00
} ,
{
"question" : {
2022-02-04 15:48:26 +01:00
"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"
2022-01-31 00:39:54 +01:00
} ,
2022-02-04 00:44:09 +01:00
"mappings" : [
2022-01-31 00:39:54 +01:00
{
2022-02-04 15:48:26 +01:00
"if" : "survey:date:={_now:date}" ,
"then" : "Vandaag gesurveyed!"
2022-01-31 00:39:54 +01:00
}
] ,
2022-02-04 15:48:26 +01:00
"id" : "trafficsign-survey:date"
}
] ,
"mapRendering" : [
2022-01-31 00:39:54 +01:00
{
2022-02-04 15:48:26 +01:00
"icon" : "./TS_bolt.svg" ,
2022-02-09 22:37:21 +01:00
iconBadges : [ {
if : "id=yes" ,
2022-02-18 23:10:27 +01:00
then : {
2022-02-09 22:37:21 +01:00
mappings : [
{
if : "id=yes" ,
then : "./Something.svg"
}
]
}
} ] ,
2022-02-04 15:48:26 +01:00
"location" : [
"point" ,
"centroid"
]
}
]
} ,
{
"id" : "notrafficsign" ,
"name" : {
"nl" : "geen verkeersbord" ,
"en" : "no traffic sign"
} ,
"source" : {
"osmTags" : {
"and" : [
2022-01-31 00:39:54 +01:00
{
2022-02-04 15:48:26 +01:00
"or" : [
"no:traffic_sign~*" ,
"not:traffic_sign~*"
]
2022-01-31 00:39:54 +01:00
} ,
2022-02-04 15:48:26 +01:00
"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"
2022-01-31 00:39:54 +01:00
} ,
{
2022-02-04 15:48:26 +01:00
"render" : {
"nl" : "Probleem bij deze situatie: {traffic_sign:issue}" ,
"en" : "Issue with this situation: {traffic_sign:issue}"
} ,
2022-01-31 00:39:54 +01:00
"question" : {
2022-02-04 15:48:26 +01:00
"nl" : "Wat is er mis met deze situatie?" ,
"en" : "What is the issue with this situation?"
2022-01-31 00:39:54 +01:00
} ,
"freeform" : {
2022-02-04 15:48:26 +01:00
"key" : "traffic_sign:issue"
} ,
"id" : "notrafficsign-traffic_sign:issue"
} ,
{
"question" : {
"nl" : "Wanneer werd deze situatie laatst gesurveyed?" ,
"en" : "When was this situation last surveyed?"
2022-01-31 00:39:54 +01:00
} ,
"render" : {
2022-02-04 15:48:26 +01:00
"nl" : "Deze situatie werd laatst gesurveyed op {survey:date}" ,
"en" : "This situation was last surveyed on {survey:date}"
} ,
"freeform" : {
"key" : "survey:date" ,
"type" : "date"
2022-01-31 00:39:54 +01:00
} ,
2022-02-04 00:44:09 +01:00
"mappings" : [
2022-01-31 00:39:54 +01:00
{
2022-02-04 15:48:26 +01:00
"if" : "survey:date:={_now:date}" ,
"then" : "Vandaag gesurveyed!"
2022-01-31 00:39:54 +01:00
}
] ,
2022-02-04 15:48:26 +01:00
"id" : "notrafficsign-survey:date"
2022-01-31 00:39:54 +01:00
}
] ,
"mapRendering" : [
{
2022-02-04 15:48:26 +01:00
"icon" : "./TS_questionmark.svg" ,
2022-01-31 00:39:54 +01:00
"location" : [
2022-02-04 15:48:26 +01:00
"point" ,
"centroid"
2022-01-31 00:39:54 +01:00
]
}
]
}
2022-02-04 15:48:26 +01:00
] ,
"defaultBackgroundId" : "Stamen.TonerLite"
2022-01-31 00:39:54 +01:00
}
2021-11-14 16:57:14 +01:00
constructor ( ) {
2022-01-14 13:58:15 +01:00
super ( [
2021-11-14 16:57:14 +01:00
[ "Walking_node_theme" , ( ) = > {
const config = LegacyThemeLoaderSpec . walking_node_theme
2022-02-04 01:05:35 +01:00
const fixed = new FixLegacyTheme ( ) . convert (
2021-12-21 18:35:31 +01:00
// @ts-ignore
config ,
"While testing" )
T . isTrue ( fixed . errors . length === 0 , "Could not fix the legacy theme" )
const theme = new LayoutConfig ( fixed . result )
2021-11-14 16:57:14 +01:00
2022-01-21 02:15:53 +01:00
} ] ,
[ "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()}"
2022-01-26 21:40:38 +01:00
} ) ;
2022-01-21 02:15:53 +01:00
shouldHave ( {
2022-01-26 21:40:38 +01:00
render : { en : "{minimap()}" }
2022-01-21 02:15:53 +01:00
} ) ;
shouldHave ( {
2022-01-26 21:40:38 +01:00
render : { en : "{minimap()}" , nl : "{minimap()}" }
2022-01-21 02:15:53 +01:00
} ) ;
shouldHave ( {
2022-01-26 21:40:38 +01:00
render : { en : "{minimap()}" , nl : "No map for the dutch!" }
2022-01-21 02:15:53 +01:00
} ) ;
2022-01-26 21:40:38 +01:00
2022-01-21 02:15:53 +01:00
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}"
} )
2022-02-04 00:44:09 +01:00
} ] ,
[ "Shadowed mappings are detected" ,
( ) = > {
2022-02-04 01:05:35 +01:00
const r = new DetectShadowedMappings ( ) . convert ( {
2022-02-04 00:44:09 +01:00
mappings : [
{
if : { or : [ "key=value" , "x=y" ] } ,
then : "Case A"
} ,
{
if : "key=value" ,
then : "Shadowed"
}
]
} , "test" ) ;
2022-02-20 02:02:09 +01:00
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" )
2022-02-18 23:10:27 +01:00
const r0 = new DetectShadowedMappings ( ) . convert ( {
2022-02-04 00:44:09 +01:00
mappings : [
{
if : { or : [ "key=value" , "x=y" ] } ,
then : "Case A"
} ,
{
if : { and : [ "key=value" , "x=y" ] } ,
then : "Shadowed"
}
]
} , "test" ) ;
2022-02-20 02:02:09 +01:00
T . isTrue ( r0 . warnings . length > 0 , "Failing case 1 is not detected" )
2022-02-04 00:44:09 +01:00
}
2022-02-04 15:48:26 +01:00
] ,
2022-02-18 23:10:27 +01:00
[ "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 )
2022-02-09 22:37:21 +01:00
2022-02-18 23:10:27 +01:00
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 )
} ] ,
2022-02-28 17:17:38 +01:00
[ "Images in simple mappings are detected" , ( ) = > {
2022-02-18 23:10:27 +01:00
const r = new DetectMappingsWithImages ( ) . convert ( {
2022-02-17 23:55:01 +01:00
"mappings" : [
2022-02-18 23:10:27 +01:00
{
"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" ) ;
2022-02-20 00:44:38 +01:00
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" ) ;
2022-02-18 23:10:27 +01:00
} ] ,
2022-02-28 17:17:38 +01:00
[ "Images in 'thens' are detected in QuestionableTagRenderings" , ( ) = > {
2022-02-19 02:45:15 +01:00
const r = new ExtractImages ( true , new Map < string , any > ( ) ) . convert ( < any > {
2022-02-18 23:10:27 +01:00
"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" ) ;
2022-02-28 18:52:28 +01:00
T . isTrue ( images . findIndex ( img = > img == "./assets/layers/bike_parking/staple.svg" ) >= 0 , "staple.svg not mentioned" ) ;
2022-02-18 23:10:27 +01:00
T . isTrue ( images . findIndex ( img = > img == "./assets/layers/bike_parking/bollard.svg" ) >= 0 , "bollard.svg not mentioned" ) ;
2022-02-28 17:17:38 +01:00
} ] ,
[ "Rotation and colours is not detected as image" , ( ) = > {
const r = new ExtractImages ( true , new Map < string , any > ( ) ) . convert ( < any > {
"layers" : [
{
mapRendering : [
{
2022-02-28 18:52:28 +01:00
"location" : [ "point" , "centroid" ] ,
2022-02-28 17:17:38 +01:00
"icon" : "pin:black" ,
rotation : 180 ,
iconSize : "40,40,center"
}
]
}
]
} , "test" ) ;
const images = r . result
T . isTrue ( images . length > 0 , "No images found" ) ;
2022-02-28 18:52:28 +01:00
T . isTrue ( images . length < 2 , "To much images found: " + images . join ( ", " ) ) ;
2022-02-28 17:17:38 +01:00
T . isTrue ( images [ 0 ] === "pin" , "pin not mentioned" ) ;
2022-02-28 18:52:28 +01:00
} ] ,
[ "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 ) )
}
]
2021-11-14 16:57:14 +01:00
]
) ;
}
}