diff --git a/UI/OpeningHours/OpeningHours.ts b/UI/OpeningHours/OpeningHours.ts
index 1c8a546b9..d918ed232 100644
--- a/UI/OpeningHours/OpeningHours.ts
+++ b/UI/OpeningHours/OpeningHours.ts
@@ -32,6 +32,32 @@ export class OH {
return Utils.TwoDigits(h) + ":" + Utils.TwoDigits(m);
}
+ /**
+ * const rules = [{weekday: 6,endHour: 17,endMinutes: 0,startHour: 13,startMinutes: 0},
+ * {weekday: 1,endHour: 12,endMinutes: 0,startHour: 10,startMinutes: 0}]
+ * OH.ToString(rules) // => "Tu 10:00-12:00; Su 13:00-17:00"
+ *
+ * const rules = [{weekday: 3,endHour: 17,endMinutes: 0,startHour: 13,startMinutes: 0}, {weekday: 1,endHour: 12,endMinutes: 0,startHour: 10,startMinutes: 0}]
+ * OH.ToString(rules) // => "Tu 10:00-12:00; Th 13:00-17:00"
+ *
+ * const rules = [ { weekday: 1, endHour: 17, endMinutes: 0, startHour: 13, startMinutes: 0 }, { weekday: 1, endHour: 12, endMinutes: 0, startHour: 10, startMinutes: 0 }]);
+ * OH.ToString(rules) // => "Tu 10:00-12:00, 13:00-17:00"
+ *
+ * const rules = [ { weekday: 0, endHour: 12, endMinutes: 0, startHour: 10, startMinutes: 0 }, { weekday: 0, endHour: 17, endMinutes: 0, startHour: 13, startMinutes: 0}, { weekday: 1, endHour: 17, endMinutes: 0, startHour: 13, startMinutes: 0 }, { weekday: 1, endHour: 12, endMinutes: 0, startHour: 10, startMinutes: 0 }];
+ * OH.ToString(rules) // => "Mo-Tu 10:00-12:00, 13:00-17:00"
+ *
+ * // should merge overlapping opening hours
+ * const timerange0 = {weekday: 1, endHour: 23, endMinutes: 30, startHour: 23, startMinutes: 0 }
+ * const touchingTimeRange = { weekday: 1, endHour: 0, endMinutes: 0, startHour: 23, startMinutes: 30 }
+ * OH.ToString(OH.MergeTimes([timerange0, touchingTimeRange])) // => "Tu 23:00-00:00"
+ *
+ * // should merge touching opening hours
+ * const timerange0 = {weekday: 1, endHour: 23, endMinutes: 30, startHour: 23, startMinutes: 0 }
+ * const overlappingTimeRange = { weekday: 1, endHour: 24, endMinutes: 0, startHour: 23, startMinutes: 30 }
+ * OH.ToString(OH.MergeTimes([timerange0, overlappingTimeRange])) // => "Tu 23:00-00:00"
+ *
+ */
+
public static ToString(ohs: OpeningHour[]) {
if (ohs.length == 0) {
return "";
@@ -86,8 +112,16 @@ export class OH {
/**
* Merge duplicate opening-hour element in place.
* Returns true if something changed
- * @param ohs
- * @constructor
+ *
+ * // should merge overlapping opening hours
+ * const oh1: OpeningHour = { weekday: 0, startHour: 10, startMinutes: 0, endHour: 11, endMinutes: 0 };
+ * const oh0: OpeningHour = { weekday: 0, startHour: 10, startMinutes: 30, endHour: 12, endMinutes: 0 };
+ * OH.MergeTimes([oh0, oh1]) // => [{ weekday: 0, startHour: 10, startMinutes: 0, endHour: 12, endMinutes: 0 }]
+ *
+ * // should merge touching opening hours
+ * const oh1: OpeningHour = { weekday: 0, startHour: 10, startMinutes: 0, endHour: 11, endMinutes: 0 };
+ * const oh0: OpeningHour = { weekday: 0, startHour: 11, startMinutes: 0, endHour: 12, endMinutes: 0 };
+ * OH.MergeTimes([oh0, oh1]) // => [{ weekday: 0, startHour: 10, startMinutes: 0, endHour: 12, endMinutes: 0 }]
*/
public static MergeTimes(ohs: OpeningHour[]): OpeningHour[] {
const queue = ohs.map(oh => {
@@ -248,6 +282,7 @@ export class OH {
* rules[0].weekday // => 0
* rules[0].startHour // => 11
* rules[3].endHour // => 19
+ *
*/
public static ParseRule(rule: string): OpeningHour[] {
try {
diff --git a/UI/i18n/Translation.ts b/UI/i18n/Translation.ts
index a9a5d3909..7c7027709 100644
--- a/UI/i18n/Translation.ts
+++ b/UI/i18n/Translation.ts
@@ -209,6 +209,13 @@ export class Translation extends BaseUIElement {
return new Translation(tr);
}
+ /**
+ * Extracts all images (including HTML-images) from all the embedded translations
+ *
+ * // should detect sources of
+ * const tr = new Translation({en: "XYZ XYZ XYZ "})
+ * new Set(tr.ExtractImages(false)) // new Set(["a.svg", "b.svg", "some image.svg"])
+ */
public ExtractImages(isIcon = false): string[] {
const allIcons: string[] = []
for (const key in this.translations) {
diff --git a/testLegacy/ImageAttribution.spec.ts b/testLegacy/ImageAttribution.spec.ts
deleted file mode 100644
index 86b394a79..000000000
--- a/testLegacy/ImageAttribution.spec.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import {equal} from "assert";
-import T from "./TestHelper";
-import {Translation} from "../UI/i18n/Translation";
-import * as cyclofix from "../assets/generated/themes/cyclofix.json"
-import {ExtractImages} from "../Models/ThemeConfig/Conversion/FixImages";
-
-export default class ImageAttributionSpec extends T {
- constructor() {
- super([
- [
- "Should find all the images",
- () => {
- const images = new Set(new ExtractImages(true, new Map()).convertStrict( cyclofix, "test"))
- const expectedValues = [
- './assets/layers/bike_repair_station/repair_station.svg',
- './assets/layers/bike_repair_station/repair_station_pump.svg',
- './assets/layers/bike_repair_station/broken_pump.svg',
- './assets/layers/bike_repair_station/pump.svg',
- './assets/themes/cyclofix/fietsambassade_gent_logo_small.svg',
- './assets/layers/bike_repair_station/pump_example_manual.jpg',
- './assets/layers/bike_repair_station/pump_example.png',
- './assets/layers/bike_repair_station/pump_example_round.jpg',
- './assets/layers/bike_repair_station/repair_station_example_2.jpg',
- 'close']
- for (const expected of expectedValues) {
- T.isTrue(images.has(expected), expected + " not found")
- }
- }
- ],
- [
- "Test image discovery regex",
- () => {
- const tr = new Translation({en: "XYZ XYZ XYZ "})
- const images = new Set(tr.ExtractImages(false));
- equal(3, images.size)
- T.isTrue(images.has("a.svg"), "a.svg not found")
- T.isTrue(images.has("b.svg"), "b.svg not found")
- T.isTrue(images.has("some image.svg"), "some image.svg not found")
-
- }
- ]
-
- ]);
- }
-}
\ No newline at end of file
diff --git a/testLegacy/Tag.spec.ts b/testLegacy/Tag.spec.ts
deleted file mode 100644
index c56a89da5..000000000
--- a/testLegacy/Tag.spec.ts
+++ /dev/null
@@ -1,297 +0,0 @@
-import {equal} from "assert";
-import T from "./TestHelper";
-import Locale from "../UI/i18n/Locale";
-import {OH, OpeningHour} from "../UI/OpeningHours/OpeningHours";
-import {Tag} from "../Logic/Tags/Tag";
-import {And} from "../Logic/Tags/And";
-import {TagUtils} from "../Logic/Tags/TagUtils";
-import TagRenderingConfig from "../Models/ThemeConfig/TagRenderingConfig";
-import {RegexTag} from "../Logic/Tags/RegexTag";
-
-export default class TagSpec extends T {
-
- constructor() {
- super([
- ["Parse tag rendering", (() => {
- Locale.language.setData("nl");
- const tr = new TagRenderingConfig({
- render: ({"en": "Name is {name}", "nl": "Ook een {name}"} as any),
- question: "Wat is de naam van dit object?",
- freeform: {
- key: "name",
- },
-
- mappings: [
- {
- if: "noname=yes",
- "then": "Has no name"
- }
- ],
- condition: "x="
- }, "Tests");
-
- equal(undefined, tr.GetRenderValue({"foo": "bar"}));
- equal("Has no name", tr.GetRenderValue({"noname": "yes"})?.txt);
- equal("Ook een {name}", tr.GetRenderValue({"name": "xyz"})?.txt);
- equal(undefined, tr.GetRenderValue({"foo": "bar"}));
-
- })],
- [
- "Merge touching opening hours",
- () => {
- const oh1: OpeningHour = {
- weekday: 0,
- startHour: 10,
- startMinutes: 0,
- endHour: 11,
- endMinutes: 0
- };
- const oh0: OpeningHour = {
- weekday: 0,
- startHour: 11,
- startMinutes: 0,
- endHour: 12,
- endMinutes: 0
- };
-
- const merged = OH.MergeTimes([oh0, oh1]);
- const r = merged[0];
- equal(merged.length, 1);
- equal(r.startHour, 10);
- equal(r.endHour, 12)
-
- }
- ],
- [
- "Merge overlapping opening hours",
- () => {
- const oh1: OpeningHour = {
- weekday: 0,
- startHour: 10,
- startMinutes: 0,
- endHour: 11,
- endMinutes: 0
- };
- const oh0: OpeningHour = {
- weekday: 0,
- startHour: 10,
- startMinutes: 30,
- endHour: 12,
- endMinutes: 0
- };
-
- const merged = OH.MergeTimes([oh0, oh1]);
- const r = merged[0];
- equal(merged.length, 1);
- equal(r.startHour, 10);
- equal(r.endHour, 12)
-
- }],
-
- ["JOIN OH 1", () => {
- const rules = OH.ToString([
- {
- weekday: 0,
- endHour: 12,
- endMinutes: 0,
- startHour: 10,
- startMinutes: 0
- },
- {
- weekday: 0,
- endHour: 17,
- endMinutes: 0,
- startHour: 13,
- startMinutes: 0
- },
-
-
- {
- weekday: 1,
- endHour: 17,
- endMinutes: 0,
- startHour: 13,
- startMinutes: 0
- }, {
- weekday: 1,
- endHour: 12,
- endMinutes: 0,
- startHour: 10,
- startMinutes: 0
- },
-
- ]);
- equal(rules, "Mo-Tu 10:00-12:00, 13:00-17:00");
- }],
- ["JOIN OH 2", () => {
- const rules = OH.ToString([
-
- {
- weekday: 1,
- endHour: 17,
- endMinutes: 0,
- startHour: 13,
- startMinutes: 0
- }, {
- weekday: 1,
- endHour: 12,
- endMinutes: 0,
- startHour: 10,
- startMinutes: 0
- },
-
- ]);
- equal(rules, "Tu 10:00-12:00, 13:00-17:00");
- }],
- ["JOIN OH 3", () => {
- const rules = OH.ToString([
-
- {
- weekday: 3,
- endHour: 17,
- endMinutes: 0,
- startHour: 13,
- startMinutes: 0
- }, {
- weekday: 1,
- endHour: 12,
- endMinutes: 0,
- startHour: 10,
- startMinutes: 0
- },
-
- ]);
- equal(rules, "Tu 10:00-12:00; Th 13:00-17:00");
- }],
- ["JOIN OH 3", () => {
- const rules = OH.ToString([
-
- {
- weekday: 6,
- endHour: 17,
- endMinutes: 0,
- startHour: 13,
- startMinutes: 0
- }, {
- weekday: 1,
- endHour: 12,
- endMinutes: 0,
- startHour: 10,
- startMinutes: 0
- },
-
- ]);
- equal(rules, "Tu 10:00-12:00; Su 13:00-17:00");
- }],
- ["JOIN OH with end hours", () => {
- const rules = OH.ToString(
- OH.MergeTimes([
-
- {
- weekday: 1,
- endHour: 23,
- endMinutes: 30,
- startHour: 23,
- startMinutes: 0
- }, {
- weekday: 1,
- endHour: 24,
- endMinutes: 0,
- startHour: 23,
- startMinutes: 30
- },
-
- ]));
- equal(rules, "Tu 23:00-00:00");
- }],
- ["JOIN OH with overflowed hours", () => {
- const rules = OH.ToString(
- OH.MergeTimes([
-
- {
- weekday: 1,
- endHour: 23,
- endMinutes: 30,
- startHour: 23,
- startMinutes: 0
- }, {
- weekday: 1,
- endHour: 0,
- endMinutes: 0,
- startHour: 23,
- startMinutes: 30
- },
-
- ]));
- equal(rules, "Tu 23:00-00:00");
- }],
- ["Regression", () => {
-
- const config = {
- "#": "Bottle refill",
- "question": {
- "en": "How easy is it to fill water bottles?",
- "nl": "Hoe gemakkelijk is het om drinkbussen bij te vullen?",
- "de": "Wie einfach ist es, Wasserflaschen zu füllen?"
- },
- "mappings": [
- {
- "if": "bottle=yes",
- "then": {
- "en": "It is easy to refill water bottles",
- "nl": "Een drinkbus bijvullen gaat makkelijk",
- "de": "Es ist einfach, Wasserflaschen nachzufüllen"
- }
- },
- {
- "if": "bottle=no",
- "then": {
- "en": "Water bottles may not fit",
- "nl": "Een drinkbus past moeilijk",
- "de": "Wasserflaschen passen möglicherweise nicht"
- }
- }
- ]
- };
-
- const tagRendering = new TagRenderingConfig(config, "test");
- equal(true, tagRendering.IsKnown({bottle: "yes"}))
- equal(false, tagRendering.IsKnown({}))
- }],
- [
- "Tag matches a lazy property",
- () => {
- const properties = {}
- const key = "_key"
- Object.defineProperty(properties, key, {
- configurable: true,
- get: function () {
- delete properties[key]
- properties[key] = "yes"
- return "yes"
- }
- })
- const filter = new Tag("_key", "yes")
- T.isTrue(filter.matchesProperties(properties), "Lazy value not matched")
- }
- ],
- [
- "RegextTag matches a lazy property",
- () => {
- const properties = {}
- const key = "_key"
- Object.defineProperty(properties, key, {
- configurable: true,
- get: function () {
- delete properties[key]
- properties[key] = "yes"
- return "yes"
- }
- })
- const filter = TagUtils.Tag("_key~*")
- T.isTrue(filter.matchesProperties(properties), "Lazy value not matched")
- }
- ]]);
- }
-
-}
diff --git a/testLegacy/TestAll.ts b/testLegacy/TestAll.ts
index 3d3078925..36c9e7e61 100644
--- a/testLegacy/TestAll.ts
+++ b/testLegacy/TestAll.ts
@@ -1,50 +1,32 @@
-import TagSpec from "./Tag.spec";
-import ImageAttributionSpec from "./ImageAttribution.spec";
import GeoOperationsSpec from "./GeoOperations.spec";
-import ThemeSpec from "./Theme.spec";
-import UtilsSpec from "./Utils.spec";
import OsmObjectSpec from "./OsmObject.spec";
import ScriptUtils from "../scripts/ScriptUtils";
-import UnitsSpec from "./Units.spec";
import RelationSplitHandlerSpec from "./RelationSplitHandler.spec";
import SplitActionSpec from "./SplitAction.spec";
import {Utils} from "../Utils";
-import TileFreshnessCalculatorSpec from "./TileFreshnessCalculator.spec";
import ImageProviderSpec from "./ImageProvider.spec";
-import ActorsSpec from "./Actors.spec";
import ReplaceGeometrySpec from "./ReplaceGeometry.spec";
import LegacyThemeLoaderSpec from "./LegacyThemeLoader.spec";
import T from "./TestHelper";
import CreateNoteImportLayerSpec from "./CreateNoteImportLayer.spec";
import CreateCacheSpec from "./CreateCache.spec";
-import CodeQualitySpec from "./CodeQuality.spec";
import ImportMultiPolygonSpec from "./ImportMultiPolygon.spec";
import ChangesetHandlerSpec from "./ChangesetHandler.spec";
-import ChangesSpec from "./Changes.spec";
async function main() {
const allTests: T[] = [
- new ChangesSpec(),
new ChangesetHandlerSpec(),
new OsmObjectSpec(),
- new TagSpec(),
- new ImageAttributionSpec(),
new GeoOperationsSpec(),
- new ThemeSpec(),
- new UtilsSpec(),
- new UnitsSpec(),
new RelationSplitHandlerSpec(),
new SplitActionSpec(),
- new TileFreshnessCalculatorSpec(),
new ImageProviderSpec(),
- new ActorsSpec(),
new ReplaceGeometrySpec(),
new LegacyThemeLoaderSpec(),
new CreateNoteImportLayerSpec(),
new CreateCacheSpec(),
- new CodeQualitySpec(),
new ImportMultiPolygonSpec(),
]
ScriptUtils.fixUtils();
diff --git a/testLegacy/TestHelper.ts b/testLegacy/TestHelper.ts
index dc88dc6a8..0c56d4150 100644
--- a/testLegacy/TestHelper.ts
+++ b/testLegacy/TestHelper.ts
@@ -8,12 +8,6 @@ export default class T {
this._tests = tests;
}
- static assertContains(needle: string, actual: string) {
- if (actual.indexOf(needle) < 0) {
- throw `The substring ${needle} was not found`
- }
- }
-
static isTrue(b: boolean, msg: string) {
if (!b) {
throw "Expected true, but got false: " + msg
diff --git a/tests/Logic/Tags/LazyMatching.spec.ts b/tests/Logic/Tags/LazyMatching.spec.ts
new file mode 100644
index 000000000..c46bf88da
--- /dev/null
+++ b/tests/Logic/Tags/LazyMatching.spec.ts
@@ -0,0 +1,41 @@
+import {describe} from 'mocha'
+import {expect} from 'chai'
+import {TagUtils} from "../../../Logic/Tags/TagUtils";
+import T from "../../../testLegacy/TestHelper";
+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;
+
+ })
+})
diff --git a/tests/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts b/tests/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts
index 35dac4a59..6b6043491 100644
--- a/tests/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts
+++ b/tests/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts
@@ -1,14 +1,14 @@
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";
+import {ExtractImages} from "../../../../Models/ThemeConfig/Conversion/FixImages";
+import * as cyclofix from "../../../../assets/generated/themes/cyclofix.json"
const themeConfigJson: LayoutConfigJson = {
@@ -52,3 +52,24 @@ describe("PrepareTheme", () => {
})
})
+
+
+describe("ExtractImages", () => {
+ it("should find all images in a themefile", () => {
+ const images = new Set(new ExtractImages(true, new Map()).convertStrict( 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)
+ }
+ })
+})
\ No newline at end of file
diff --git a/tests/Models/ThemeConfig/TagRenderingConfig.spec.ts b/tests/Models/ThemeConfig/TagRenderingConfig.spec.ts
new file mode 100644
index 000000000..aa38aaf87
--- /dev/null
+++ b/tests/Models/ThemeConfig/TagRenderingConfig.spec.ts
@@ -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
+ })
+ })
+})
+