More refactoring of the tests

This commit is contained in:
pietervdvn 2022-03-18 13:04:12 +01:00
parent 308ab74a08
commit 97c88af619
11 changed files with 199 additions and 247 deletions

View file

@ -2,9 +2,14 @@ import {TagsFilter} from "./TagsFilter";
import {Or} from "./Or";
import {TagUtils} from "./TagUtils";
// @ts-ignore
import {Tag} from "./Tag";// needed for tests
// @ts-ignore
import {RegexTag} from "./RegexTag";// needed for tests
export class And extends TagsFilter {
public and: TagsFilter[]
constructor(and: TagsFilter[]) {
super();
this.and = and
@ -40,6 +45,10 @@ export class And extends TagsFilter {
return true;
}
/**
* const and = new And([new Tag("boundary","protected_area"), new RegexTag("protect_class","98",true)])
* and.asOverpass() // => [ "[\"boundary\"=\"protected_area\"][\"protect_class\"!~\"^98$\"]" ]
*/
asOverpass(): string[] {
let allChoices: string[] = null;
for (const andElement of this.and) {
@ -73,6 +82,23 @@ export class And extends TagsFilter {
return true;
}
/**
* const t0 = new And([
* new Tag("valves:special", "A"),
* new Tag("valves", "A")
* ])
* const t1 = new And([new Tag("valves", "A")])
* const t2 = new And([new Tag("valves", "B")])
* t0.isEquivalent(t0) // => true
* t1.isEquivalent(t1) // => true
* t2.isEquivalent(t2) // => true
* t0.isEquivalent(t1) // => false
* t0.isEquivalent(t2) // => false
* t1.isEquivalent(t0) // => false
* t1.isEquivalent(t2) // => false
* t2.isEquivalent(t0) // => false
* t2.isEquivalent(t1) // => false
*/
isEquivalent(other: TagsFilter): boolean {
if (!(other instanceof And)) {
return false;

View file

@ -2,6 +2,10 @@ import {TagsFilter} from "./TagsFilter";
import {TagUtils} from "./TagUtils";
import {And} from "./And";
// @ts-ignore
import {Tag} from "./Tag";// needed for tests
// @ts-ignore
import {RegexTag} from "./RegexTag";// needed for tests
export class Or extends TagsFilter {
public or: TagsFilter[]
@ -21,6 +25,15 @@ export class Or extends TagsFilter {
return false;
}
/**
* const and = new And([new Tag("boundary","protected_area"), new RegexTag("protect_class","98",true)])
* const or = new Or([and, new Tag("leisure", "nature_reserve"])
* or.asOverpass() // => [ "[\"boundary\"=\"protected_area\"][\"protect_class\"!~\"^98$\"]", "[\"leisure\"=\"nature_reserve\"]" ]
*
* // should fuse nested ors into a single list
* const or = new Or([new Tag("key","value"), new Or([new Tag("key1","value1"), new Tag("key2","value2")])])
* or.asOverpass() // => [ `["key"="value"]`, `["key1"="value1"]`, `["key2"="value2"]` ]
*/
asOverpass(): string[] {
const choices = [];
for (const tagsFilter of this.or) {

View file

@ -42,6 +42,12 @@ export class RegexTag extends TagsFilter {
return r.source;
}
/**
* new RegexTag("a", /^[xyz]$/).asOverpass() // => [ `["a"~"^[xyz]$"]` ]
*
* // A wildcard regextag should only give the key
* new RegexTag("a", /^..*$/).asOverpass() // => [ `["a"]` ]
*/
asOverpass(): string[] {
const inv =this.invert ? "!" : ""
if (typeof this.key !== "string") {
@ -89,7 +95,29 @@ export class RegexTag extends TagsFilter {
* notRegex.matchesProperties({"x": "z"}) // => true
* notRegex.matchesProperties({"x": ""}) // => true
* notRegex.matchesProperties({}) // => true
*
* const bicycleTubeRegex = new RegexTag("vending", /^.*bicycle_tube.*$/)
* bicycleTubeRegex.matchesProperties({"vending": "bicycle_tube"}) // => true
* bicycleTubeRegex.matchesProperties({"vending": "something;bicycle_tube"}) // => true
* bicycleTubeRegex.matchesProperties({"vending": "bicycle_tube;something"}) // => true
* bicycleTubeRegex.matchesProperties({"vending": "xyz;bicycle_tube;something"}) // => true
*
* const nameStartsWith = new RegexTag("name", /^[sS]peelbox.*$/)
* nameStartsWith.matchesProperties({"name": "Speelbos Sint-Anna"} => true
* nameStartsWith.matchesProperties({"name": "speelbos Sint-Anna"} => true
* nameStartsWith.matchesProperties({"name": "Sint-Anna"} => false
* nameStartsWith.matchesProperties({"name": ""} => false
*
* const notEmptyList = new RegexTag("xyz", /^\[\]$/, true)
* notEmptyList.matchesProperties({"xyz": undefined}) // => true
* notEmptyList.matchesProperties({"xyz": "[]"}) // => false
* notEmptyList.matchesProperties({"xyz": "[\"abc\"]"}) // => true
*
* const importMatch = new RegexTag("tags", /(^|.*;)amenity=public_bookcase($|;.*)/)
* importMatch.matchesProperties({"tags": "amenity=public_bookcase;name=test"}) // =>true
* importMatch.matchesProperties({"tags": "amenity=public_bookcase"}) // =>true
* importMatch.matchesProperties({"tags": "name=test;amenity=public_bookcase"}) // =>true
* importMatch.matchesProperties({"tags": "amenity=bench"}) // =>false
*/
matchesProperties(tags: any): boolean {
if (typeof this.key === "string") {

View file

@ -46,6 +46,14 @@ export default class SubstitutingTag implements TagsFilter {
return !this._invert;
}
/**
* const assign = new SubstitutingTag("survey:date", "{_date:now}")
* assign.matchesProperties({"survey:date": "2021-03-29", "_date:now": "2021-03-29"}) // => true
* assign.matchesProperties({"survey:date": "2021-03-29", "_date:now": "2021-01-01"}) // => false
* assign.matchesProperties({"survey:date": "2021-03-29"}) // => false
* assign.matchesProperties({"_date:now": "2021-03-29"}) // => false
* assign.matchesProperties({"some_key": "2021-03-29"}) // => false
*/
matchesProperties(properties: any): boolean {
const value = properties[this._key];
if (value === undefined || value === "") {

View file

@ -167,6 +167,21 @@ export class TagUtils {
return new Tag(tag[0], tag[1]);
}
/**
* Parses a tag configuration (a json) into a TagsFilter
*
* TagUtils.Tag("key=value") // => new Tag("key", "value")
* TagUtils.Tag("key=") // => new Tag("key", "")
* TagUtils.Tag("key!=") // => new RegexTag("key", "^..*$", true)
* TagUtils.Tag("key!=value") // => new RegexTag("key", /^value$/, true)
* TagUtils.Tag("vending~.*bicycle_tube.*") // => new RegexTag("vending", /^.*bicycle_tube.*$/)
* TagUtils.Tag("x!~y") // => new RegexTag("x", /^y$/, true)
* TagUtils.Tag({"and": ["key=value", "x=y"]}) // => new And([new Tag("key","value"), new Tag("x","y")])
* TagUtils.Tag("name~[sS]peelbos.*") // => new RegexTag("name", /^[sS]peelbos.*$/)
* TagUtils.Tag("survey:date:={_date:now}") // => new SubstitutingTag("survey:date", "{_date:now}")
* TagUtils.Tag("xyz!~\\[\\]") // => new RegexTag("xyz", /^\[\]$/, true)
* TagUtils.Tag("tags~(^|.*;)amenity=public_bookcase($|;.*)") // => new RegexTag("tags", /(^|.*;)amenity=public_bookcase($|;.*)/)
*/
public static Tag(json: AndOrTagConfigJson | string, context: string = ""): TagsFilter {
try {
return this.TagUnsafe(json, context);

View file

@ -145,6 +145,7 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
const v = state.sharedLayers.get(layerName)
if (v === undefined) {
errors.push("Default layer " + layerName + " not found")
continue
}
if(alreadyLoaded.has(v.id)){
warnings.push("Layout "+context+" already has a layer with name "+v.id+"; skipping inclusion of this builtin layer")

View file

@ -236,6 +236,18 @@ export class OH {
* rules.length // => 7
* rules[0].startHour // => 0
* OH.ToString(rules) // => "24/7"
*
* const rules = OH.ParseRule("11:00-19:00");
* rules.length // => 7
* rules[0].weekday // => 0
* rules[0].startHour // => 11
* rules[3].endHour // => 19
*
* const rules = OH.ParseRule("Mo-Th 11:00-19:00");
* rules.length // => 4
* rules[0].weekday // => 0
* rules[0].startHour // => 11
* rules[3].endHour // => 19
*/
public static ParseRule(rule: string): OpeningHour[] {
try {

View file

@ -6,94 +6,12 @@ import {Tag} from "../Logic/Tags/Tag";
import {And} from "../Logic/Tags/And";
import {TagUtils} from "../Logic/Tags/TagUtils";
import TagRenderingConfig from "../Models/ThemeConfig/TagRenderingConfig";
import {RegexTag} from "../Logic/Tags/RegexTag";
export default class TagSpec extends T {
constructor() {
super([
["Parse tag config", (() => {
const multiMatch = TagUtils.Tag("vending~.*bicycle_tube.*") as Tag;
equal(multiMatch.matchesProperties({"vending": "bicycle_tube"}), true)
equal(multiMatch.matchesProperties({"vending": "something;bicycle_tube"}), true)
equal(multiMatch.matchesProperties({"vending": "bicycle_tube;something"}), true)
equal(multiMatch.matchesProperties({"vending": "xyz;bicycle_tube;something"}), true)
const nameStartsWith = TagUtils.Tag("name~[sS]peelbos.*")
equal(nameStartsWith.matchesProperties({"name": "Speelbos Sint-Anna"}), true)
equal(nameStartsWith.matchesProperties({"name": "speelbos Sint-Anna"}), true)
equal(nameStartsWith.matchesProperties({"name": "Sint-Anna"}), false)
equal(nameStartsWith.matchesProperties({"name": ""}), false)
const assign = TagUtils.Tag("survey:date:={_date:now}")
equal(assign.matchesProperties({"survey:date": "2021-03-29", "_date:now": "2021-03-29"}), true);
equal(assign.matchesProperties({"survey:date": "2021-03-29", "_date:now": "2021-01-01"}), false);
equal(assign.matchesProperties({"survey:date": "2021-03-29"}), false);
equal(assign.matchesProperties({"_date:now": "2021-03-29"}), false);
equal(assign.matchesProperties({"some_key": "2021-03-29"}), false);
const notEmptyList = TagUtils.Tag("xyz!~\\[\\]")
equal(notEmptyList.matchesProperties({"xyz": undefined}), true);
equal(notEmptyList.matchesProperties({"xyz": "[]"}), false);
equal(notEmptyList.matchesProperties({"xyz": "[\"abc\"]"}), true);
let compare = TagUtils.Tag("key<=5")
equal(compare.matchesProperties({"key": undefined}), false);
equal(compare.matchesProperties({"key": "6"}), false);
equal(compare.matchesProperties({"key": "5"}), true);
equal(compare.matchesProperties({"key": "4"}), true);
compare = TagUtils.Tag("key<5")
equal(compare.matchesProperties({"key": undefined}), false);
equal(compare.matchesProperties({"key": "6"}), false);
equal(compare.matchesProperties({"key": "5"}), false);
equal(compare.matchesProperties({"key": "4.2"}), true);
compare = TagUtils.Tag("key>5")
equal(compare.matchesProperties({"key": undefined}), false);
equal(compare.matchesProperties({"key": "6"}), true);
equal(compare.matchesProperties({"key": "5"}), false);
equal(compare.matchesProperties({"key": "4.2"}), false);
compare = TagUtils.Tag("key>=5")
equal(compare.matchesProperties({"key": undefined}), false);
equal(compare.matchesProperties({"key": "6"}), true);
equal(compare.matchesProperties({"key": "5"}), true);
equal(compare.matchesProperties({"key": "4.2"}), false);
const importMatch = TagUtils.Tag("tags~(^|.*;)amenity=public_bookcase($|;.*)")
equal(importMatch.matchesProperties({"tags": "amenity=public_bookcase;name=test"}), true)
equal(importMatch.matchesProperties({"tags": "amenity=public_bookcase"}), true)
equal(importMatch.matchesProperties({"tags": "name=test;amenity=public_bookcase"}), true)
equal(importMatch.matchesProperties({"tags": "amenity=bench"}), false)
})],
["Is equivalent test", (() => {
const t0 = new And([
new Tag("valves:special", "A"),
new Tag("valves", "A")
])
const t1 = new And([
new Tag("valves", "A")
])
const t2 = new And([
new Tag("valves", "B")
])
equal(true, t0.isEquivalent(t0))
equal(true, t1.isEquivalent(t1))
equal(true, t2.isEquivalent(t2))
equal(false, t0.isEquivalent(t1))
equal(false, t0.isEquivalent(t2))
equal(false, t1.isEquivalent(t0))
equal(false, t1.isEquivalent(t2))
equal(false, t2.isEquivalent(t0))
equal(false, t2.isEquivalent(t1))
})],
["Parse tag rendering", (() => {
Locale.language.setData("nl");
const tr = new TagRenderingConfig({
@ -118,51 +36,6 @@ export default class TagSpec extends T {
equal(undefined, tr.GetRenderValue({"foo": "bar"}));
})],
[
"Test not with overpass",
() => {
const t = {
and: [
"boundary=protected_area",
"protect_class!=98"
]
}
const filter = TagUtils.Tag(t)
const overpass = filter.asOverpass();
console.log(overpass)
equal(overpass[0], "[\"boundary\"=\"protected_area\"][\"protect_class\"!~\"^98$\"]")
const or = {
or: [
"leisure=nature_reserve",
t
]
}
const overpassOr = TagUtils.Tag(or).asOverpass()
equal(2, overpassOr.length)
equal(overpassOr[1], "[\"boundary\"=\"protected_area\"][\"protect_class\"!~\"^98$\"]")
const orInOr = {
or: [
"amenity=drinking_water",
or
]
}
const overpassOrInor = TagUtils.Tag(orInOr).asOverpass()
equal(3, overpassOrInor.length)
}
],
[
"Test regex to overpass",() => {
/*(Specifiation to parse, expected value for new RegexTag(spec).asOverpass()[0]) */
[["a~*", `"a"`],
["a~[xyz]",`"a"~"^[xyz]$"`]].forEach(([spec, expected]) =>{
T.equals(`[${expected}]`, TagUtils.Tag(
spec
).asOverpass()[0], "RegexRendering failed")
} )
}
],
[
"Merge touching opening hours",
() => {
@ -214,21 +87,7 @@ export default class TagSpec extends T {
equal(r.endHour, 12)
}],
["Parse OH 1", () => {
const rules = OH.ParseRule("11:00-19:00");
equal(rules.length, 7);
equal(rules[0].weekday, 0);
equal(rules[0].startHour, 11);
equal(rules[3].endHour, 19);
}],
["Parse OH 2", () => {
const rules = OH.ParseRule("Mo-Th 11:00-19:00");
equal(rules.length, 4);
equal(rules[0].weekday, 0);
equal(rules[0].startHour, 11);
equal(rules[3].endHour, 19);
}],
["JOIN OH 1", () => {
const rules = OH.ToString([
{
@ -432,14 +291,7 @@ export default class TagSpec extends T {
const filter = TagUtils.Tag("_key~*")
T.isTrue(filter.matchesProperties(properties), "Lazy value not matched")
}
],
["test date comparison", () => {
const filter = TagUtils.Tag("date_created<2022-01-07")
T.isFalse(filter.matchesProperties({"date_created": "2022-01-08"}), "Date comparison: expected a match")
T.isTrue(filter.matchesProperties({"date_created": "2022-01-01"}), "Date comparison: didn't expect a match")
}]]);
]]);
}
}

View file

@ -1,54 +0,0 @@
import T from "./TestHelper";
import * as assert from "assert";
import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson";
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
import * as bookcaseLayer from "../assets/generated/layers/public_bookcase.json"
import {TagRenderingConfigJson} from "../Models/ThemeConfig/Json/TagRenderingConfigJson";
import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson";
import Constants from "../Models/Constants";
import {PrepareTheme} from "../Models/ThemeConfig/Conversion/PrepareTheme";
export default class ThemeSpec extends T {
constructor() {
super([
["Nested overrides work", () => {
let themeConfigJson: LayoutConfigJson = {
description: "Descr",
icon: "",
layers: [
{
builtin: "public_bookcase",
override: {
source: {
geoJson: "xyz"
}
}
}
],
maintainer: "",
startLat: 0,
startLon: 0,
startZoom: 0,
title: {
en: "Title"
},
version: "",
id: "test"
}
// TOtal cheat: disable the default layers:
Constants.added_by_default.splice(0, Constants.added_by_default.length)
const sharedLayers = new Map<string, LayerConfigJson>()
sharedLayers.set("public_bookcase", bookcaseLayer["default"])
themeConfigJson = new PrepareTheme({
tagRenderings: new Map<string, TagRenderingConfigJson>(),
sharedLayers: sharedLayers
}).convertStrict( themeConfigJson, "test")
const themeConfig = new LayoutConfig(themeConfigJson);
assert.equal("xyz", themeConfig.layers[0].source.geojsonSource)
}]
]);
}
}

View file

@ -1,56 +1,53 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import {TagUtils} from "../../../Logic/Tags/TagUtils";
import {Tag} from "../../../Logic/Tags/Tag";
import {RegexTag} from "../../../Logic/Tags/RegexTag";
import {And} from "../../../Logic/Tags/And";
import {equal} from "assert";
import T from "../../../testLegacy/TestHelper";
describe("TagUtils", () => {
describe("ParseTag", () => {
it("should parse a simple key=value tag", () => {
const tag = TagUtils.Tag("key=value") as Tag;
expect(tag.key).eq( "key");
expect(tag.value).eq("value");
})
it("should parse an 'empty spec' key= tag", () => {
const tag = TagUtils.Tag("key=") as Tag;
expect(tag.key).eq( "key");
expect(tag.value).eq("");
})
it("should parse a 'not-empty spec' key!= tag", () => {
const tag = TagUtils.Tag("key!=") as RegexTag;
expect(tag.invert).true
expect(tag.key).eq( "key");
expect(tag.value["source"]).eq("^..*$");
})
it("should parse a normal 'not-equals-value' key!=value tag", () => {
const tag = TagUtils.Tag("key!=value") as RegexTag
expect(tag.invert).true
expect(tag.key).eq( "key");
expect(tag.value["source"]).eq("^value$");
})
describe("ParseTag", () => {
it("should refuse a key!=* tag", () => {
expect(() => TagUtils.Tag("key!=*")).to.throw();
})
it("should parse regextags", () => {
const notReg = TagUtils.Tag("x!~y") as RegexTag;
expect(notReg.key).eq("x")
expect(notReg.value["source"]).eq("^y$")
expect(notReg.invert).true
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 parse and", () => {
const and = TagUtils.Tag({"and": ["key=value", "x=y"]}) as And;
expect(and.and[0]["key"]).eq("key")
expect(and.and[0]["value"]).eq("value")
expect(and.and[1]["key"]).eq("x")
expect(and.and[1]["value"]).eq("y")
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
})
})
})

View file

@ -0,0 +1,54 @@
import {describe} from 'mocha'
import {expect} from 'chai'
import {LayoutConfigJson} from "../../../../Models/ThemeConfig/Json/LayoutConfigJson";
import Constants from "../../../../Models/Constants";
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 assert from "assert";
import * as bookcaseLayer from "../../../../assets/generated/layers/public_bookcase.json"
import LayerConfig from "../../../../Models/ThemeConfig/LayerConfig";
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 apply overrideAll", () => {
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")
})
})