From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- intl/l10n/test/test_l10nregistry.js | 563 ++++++++++++++++++++++++++++++++++++ 1 file changed, 563 insertions(+) create mode 100644 intl/l10n/test/test_l10nregistry.js (limited to 'intl/l10n/test/test_l10nregistry.js') diff --git a/intl/l10n/test/test_l10nregistry.js b/intl/l10n/test/test_l10nregistry.js new file mode 100644 index 0000000000..cbbb1e7316 --- /dev/null +++ b/intl/l10n/test/test_l10nregistry.js @@ -0,0 +1,563 @@ +/* Any copyrighequal dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const {setTimeout} = ChromeUtils.importESModule("resource://gre/modules/Timer.sys.mjs"); + +const l10nReg = new L10nRegistry(); + +add_task(function test_methods_presence() { + equal(typeof l10nReg.generateBundles, "function"); + equal(typeof l10nReg.generateBundlesSync, "function"); + equal(typeof l10nReg.getAvailableLocales, "function"); + equal(typeof l10nReg.registerSources, "function"); + equal(typeof l10nReg.removeSources, "function"); + equal(typeof l10nReg.updateSources, "function"); +}); + +/** + * Test that passing empty resourceIds list works. + */ +add_task(async function test_empty_resourceids() { + const fs = []; + + const source = L10nFileSource.createMock("test", "", ["en-US"], "/localization/{locale}", fs); + l10nReg.registerSources([source]); + + const bundles = l10nReg.generateBundles(["en-US"], []); + + const done = (await bundles.next()).done; + + equal(done, true); + + // cleanup + l10nReg.clearSources(); +}); + +/** + * Test that passing empty sources list works. + */ +add_task(async function test_empty_sources() { + const fs = []; + const bundles = l10nReg.generateBundlesSync(["en-US"], fs); + + const done = (await bundles.next()).done; + + equal(done, true); + + // cleanup + l10nReg.clearSources(); +}); + +/** + * This test tests generation of a proper context for a single + * source scenario + */ +add_task(async function test_methods_calling() { + const fs = [ + { path: "/localization/en-US/browser/menu.ftl", source: "key = Value" } + ]; + const source = L10nFileSource.createMock("test", "", ["en-US"], "/localization/{locale}", fs); + l10nReg.registerSources([source]); + + const bundles = l10nReg.generateBundles(["en-US"], ["/browser/menu.ftl"]); + + const bundle = (await bundles.next()).value; + + equal(bundle.hasMessage("key"), true); + + // cleanup + l10nReg.clearSources(); +}); + +/** + * This test verifies that the public methods return expected values + * for the single source scenario + */ +add_task(async function test_has_one_source() { + const fs = [ + {path: "./app/data/locales/en-US/test.ftl", source: "key = value en-US"} + ]; + let oneSource = L10nFileSource.createMock("app", "", ["en-US"], "./app/data/locales/{locale}/", fs); + l10nReg.registerSources([oneSource]); + + + // has one source + + equal(l10nReg.getSourceNames().length, 1); + equal(l10nReg.hasSource("app"), true); + + + // returns a single context + + let bundles = l10nReg.generateBundles(["en-US"], ["test.ftl"]); + let bundle0 = (await bundles.next()).value; + equal(bundle0.hasMessage("key"), true); + + equal((await bundles.next()).done, true); + + + // returns no contexts for missing locale + + bundles = l10nReg.generateBundles(["pl"], ["test.ftl"]); + + equal((await bundles.next()).done, true); + + // cleanup + l10nReg.clearSources(); +}); + +/** + * This test verifies that public methods return expected values + * for the dual source scenario. + */ +add_task(async function test_has_two_sources() { + const fs = [ + { path: "./platform/data/locales/en-US/test.ftl", source: "key = platform value" }, + { path: "./app/data/locales/pl/test.ftl", source: "key = app value" } + ]; + let oneSource = L10nFileSource.createMock("platform", "", ["en-US"], "./platform/data/locales/{locale}/", fs); + let secondSource = L10nFileSource.createMock("app", "", ["pl"], "./app/data/locales/{locale}/", fs); + l10nReg.registerSources([oneSource, secondSource]); + + // has two sources + + equal(l10nReg.getSourceNames().length, 2); + equal(l10nReg.hasSource("app"), true); + equal(l10nReg.hasSource("platform"), true); + + + // returns correct contexts for en-US + + let bundles = l10nReg.generateBundles(["en-US"], ["test.ftl"]); + let bundle0 = (await bundles.next()).value; + + equal(bundle0.hasMessage("key"), true); + let msg = bundle0.getMessage("key"); + equal(bundle0.formatPattern(msg.value), "platform value"); + + equal((await bundles.next()).done, true); + + + // returns correct contexts for [pl, en-US] + + bundles = l10nReg.generateBundles(["pl", "en-US"], ["test.ftl"]); + bundle0 = (await bundles.next()).value; + equal(bundle0.locales[0], "pl"); + equal(bundle0.hasMessage("key"), true); + let msg0 = bundle0.getMessage("key"); + equal(bundle0.formatPattern(msg0.value), "app value"); + + let bundle1 = (await bundles.next()).value; + equal(bundle1.locales[0], "en-US"); + equal(bundle1.hasMessage("key"), true); + let msg1 = bundle1.getMessage("key"); + equal(bundle1.formatPattern(msg1.value), "platform value"); + + equal((await bundles.next()).done, true); + + // cleanup + l10nReg.clearSources(); +}); + +/** + * This test verifies that behavior specific to the L10nFileSource + * works correctly. + * + * In particular it tests that L10nFileSource correctly returns + * missing files as `false` instead of `undefined`. + */ +add_task(function test_indexed() { + let oneSource = new L10nFileSource("langpack-pl", "app", ["pl"], "/data/locales/{locale}/", {}, [ + "/data/locales/pl/test.ftl", + ]); + equal(oneSource.hasFile("pl", "test.ftl"), "present"); + equal(oneSource.hasFile("pl", "missing.ftl"), "missing"); +}); + +/** + * This test checks if the correct order of contexts is used for + * scenarios where a new file source is added on top of the default one. + */ +add_task(async function test_override() { + const fs = [ + { path: "/app/data/locales/pl/test.ftl", source: "key = value" }, + { path: "/data/locales/pl/test.ftl", source: "key = addon value"}, + ]; + let fileSource = L10nFileSource.createMock("app", "", ["pl"], "/app/data/locales/{locale}/", fs); + let oneSource = L10nFileSource.createMock("langpack-pl", "", ["pl"], "/data/locales/{locale}/", fs); + l10nReg.registerSources([fileSource, oneSource]); + + equal(l10nReg.getSourceNames().length, 2); + equal(l10nReg.hasSource("langpack-pl"), true); + + let bundles = l10nReg.generateBundles(["pl"], ["test.ftl"]); + let bundle0 = (await bundles.next()).value; + equal(bundle0.locales[0], "pl"); + equal(bundle0.hasMessage("key"), true); + let msg0 = bundle0.getMessage("key"); + equal(bundle0.formatPattern(msg0.value), "addon value"); + + let bundle1 = (await bundles.next()).value; + equal(bundle1.locales[0], "pl"); + equal(bundle1.hasMessage("key"), true); + let msg1 = bundle1.getMessage("key"); + equal(bundle1.formatPattern(msg1.value), "value"); + + equal((await bundles.next()).done, true); + + // cleanup + l10nReg.clearSources(); +}); + +/** + * This test verifies that new contexts are returned + * after source update. + */ +add_task(async function test_updating() { + const fs = [ + { path: "/data/locales/pl/test.ftl", source: "key = value" } + ]; + let oneSource = L10nFileSource.createMock("langpack-pl", "", ["pl"], "/data/locales/{locale}/", fs); + l10nReg.registerSources([oneSource]); + + let bundles = l10nReg.generateBundles(["pl"], ["test.ftl"]); + let bundle0 = (await bundles.next()).value; + equal(bundle0.locales[0], "pl"); + equal(bundle0.hasMessage("key"), true); + let msg0 = bundle0.getMessage("key"); + equal(bundle0.formatPattern(msg0.value), "value"); + + + const newSource = L10nFileSource.createMock("langpack-pl", "", ["pl"], "/data/locales/{locale}/", [ + { path: "/data/locales/pl/test.ftl", source: "key = new value" } + ]); + l10nReg.updateSources([newSource]); + + equal(l10nReg.getSourceNames().length, 1); + bundles = l10nReg.generateBundles(["pl"], ["test.ftl"]); + bundle0 = (await bundles.next()).value; + msg0 = bundle0.getMessage("key"); + equal(bundle0.formatPattern(msg0.value), "new value"); + + // cleanup + l10nReg.clearSources(); +}); + +/** + * This test verifies that generated contexts return correct values + * after sources are being removed. + */ +add_task(async function test_removing() { + const fs = [ + { path: "/app/data/locales/pl/test.ftl", source: "key = value" }, + { path: "/data/locales/pl/test.ftl", source: "key = addon value" }, + ]; + + let fileSource = L10nFileSource.createMock("app", "", ["pl"], "/app/data/locales/{locale}/", fs); + let oneSource = L10nFileSource.createMock("langpack-pl", "", ["pl"], "/data/locales/{locale}/", fs); + l10nReg.registerSources([fileSource, oneSource]); + + equal(l10nReg.getSourceNames().length, 2); + equal(l10nReg.hasSource("langpack-pl"), true); + + let bundles = l10nReg.generateBundles(["pl"], ["test.ftl"]); + let bundle0 = (await bundles.next()).value; + equal(bundle0.locales[0], "pl"); + equal(bundle0.hasMessage("key"), true); + let msg0 = bundle0.getMessage("key"); + equal(bundle0.formatPattern(msg0.value), "addon value"); + + let bundle1 = (await bundles.next()).value; + equal(bundle1.locales[0], "pl"); + equal(bundle1.hasMessage("key"), true); + let msg1 = bundle1.getMessage("key"); + equal(bundle1.formatPattern(msg1.value), "value"); + + equal((await bundles.next()).done, true); + + // Remove langpack + + l10nReg.removeSources(["langpack-pl"]); + + equal(l10nReg.getSourceNames().length, 1); + equal(l10nReg.hasSource("langpack-pl"), false); + + bundles = l10nReg.generateBundles(["pl"], ["test.ftl"]); + bundle0 = (await bundles.next()).value; + equal(bundle0.locales[0], "pl"); + equal(bundle0.hasMessage("key"), true); + msg0 = bundle0.getMessage("key"); + equal(bundle0.formatPattern(msg0.value), "value"); + + equal((await bundles.next()).done, true); + + // Remove app source + + l10nReg.removeSources(["app"]); + + equal(l10nReg.getSourceNames().length, 0); + + bundles = l10nReg.generateBundles(["pl"], ["test.ftl"]); + equal((await bundles.next()).done, true); + + // cleanup + l10nReg.clearSources(); +}); + +/** + * This test verifies that the logic works correctly when there's a missing + * file in the FileSource scenario. + */ +add_task(async function test_missing_file() { + const fs = [ + { path: "./app/data/locales/en-US/test.ftl", source: "key = value en-US" }, + { path: "./platform/data/locales/en-US/test.ftl", source: "key = value en-US" }, + { path: "./platform/data/locales/en-US/test2.ftl", source: "key2 = value2 en-US" }, + ]; + let oneSource = L10nFileSource.createMock("app", "", ["en-US"], "./app/data/locales/{locale}/", fs); + let twoSource = L10nFileSource.createMock("platform", "", ["en-US"], "./platform/data/locales/{locale}/", fs); + l10nReg.registerSources([oneSource, twoSource]); + + // has two sources + + equal(l10nReg.getSourceNames().length, 2); + equal(l10nReg.hasSource("app"), true); + equal(l10nReg.hasSource("platform"), true); + + + // returns a single context + + let bundles = l10nReg.generateBundles(["en-US"], ["test.ftl", "test2.ftl"]); + + // First permutation: + // [platform, platform] - both present + let bundle1 = (await bundles.next()); + equal(bundle1.value.hasMessage("key"), true); + + // Second permutation skipped: + // [platform, app] - second missing + // Third permutation: + // [app, platform] - both present + let bundle2 = (await bundles.next()); + equal(bundle2.value.hasMessage("key"), true); + + // Fourth permutation skipped: + // [app, app] - second missing + equal((await bundles.next()).done, true); + + // cleanup + l10nReg.clearSources(); +}); + +add_task(async function test_hasSource() { + equal(l10nReg.hasSource("nonsense"), false, "Non-existing source doesn't exist"); + equal(l10nReg.hasSource("app"), false, "hasSource returns true before registering a source"); + let oneSource = new L10nFileSource("app", "app", ["en-US"], "/{locale}/"); + l10nReg.registerSources([oneSource]); + equal(l10nReg.hasSource("app"), true, "hasSource returns true after registering a source"); + l10nReg.clearSources(); +}); + +/** + * This test verifies that we handle correctly a scenario where a source + * is being removed while the iterator operates. + */ +add_task(async function test_remove_source_mid_iter_cycle() { + const fs = [ + { path: "./platform/data/locales/en-US/test.ftl", source: "key = platform value" }, + { path: "./app/data/locales/pl/test.ftl", source: "key = app value" }, + ]; + let oneSource = L10nFileSource.createMock("platform", "", ["en-US"], "./platform/data/locales/{locale}/", fs); + let secondSource = L10nFileSource.createMock("app", "", ["pl"], "./app/data/locales/{locale}/", fs); + l10nReg.registerSources([oneSource, secondSource]); + + let bundles = l10nReg.generateBundles(["en-US", "pl"], ["test.ftl"]); + + let bundle0 = await bundles.next(); + + // The registry has a copy of the file sources, so it will be unaffected. + l10nReg.removeSources(["app"]); + + let bundle1 = await bundles.next(); + + equal((await bundles.next()).done, true); + + // cleanup + l10nReg.clearSources(); +}); + +add_task(async function test_metasources() { + let fs = [ + { path: "/localization/en-US/browser/menu1.ftl", source: "key1 = Value" }, + { path: "/localization/en-US/browser/menu2.ftl", source: "key2 = Value" }, + { path: "/localization/en-US/browser/menu3.ftl", source: "key3 = Value" }, + { path: "/localization/en-US/browser/menu4.ftl", source: "key4 = Value" }, + { path: "/localization/en-US/browser/menu5.ftl", source: "key5 = Value" }, + { path: "/localization/en-US/browser/menu6.ftl", source: "key6 = Value" }, + { path: "/localization/en-US/browser/menu7.ftl", source: "key7 = Value" }, + { path: "/localization/en-US/browser/menu8.ftl", source: "key8 = Value" }, + ]; + + const browser = L10nFileSource.createMock("browser", "app", ["en-US"], "/localization/{locale}", fs); + const toolkit = L10nFileSource.createMock("toolkit", "app", ["en-US"], "/localization/{locale}", fs); + const browser2 = L10nFileSource.createMock("browser2", "langpack", ["en-US"], "/localization/{locale}", fs); + const toolkit2 = L10nFileSource.createMock("toolkit2", "langpack", ["en-US"], "/localization/{locale}", fs); + l10nReg.registerSources([toolkit, browser, toolkit2, browser2]); + + let res = [ + "/browser/menu1.ftl", + "/browser/menu2.ftl", + "/browser/menu3.ftl", + "/browser/menu4.ftl", + "/browser/menu5.ftl", + "/browser/menu6.ftl", + "/browser/menu7.ftl", + {path: "/browser/menu8.ftl", optional: false}, + ]; + + const bundles = l10nReg.generateBundles(["en-US"], res); + + let nbundles = 0; + while (!(await bundles.next()).done) { + nbundles += 1; + } + + // If metasources are working properly, we'll generate 2^8 = 256 bundles for + // each metasource giving 512 bundles in total. Otherwise, we generate + // 4^8 = 65536 bundles. + equal(nbundles, 512); + + // cleanup + l10nReg.clearSources(); +}); + +/** + * This test verifies that when a required resource is missing for a locale, + * we do not produce a bundle for that locale. + */ +add_task(async function test_missing_required_resource() { + const fs = [ + { path: "./platform/data/locales/en-US/test.ftl", source: "test-key = en-US value" }, + { path: "./platform/data/locales/pl/missing-in-en-US.ftl", source: "missing-key = pl value" }, + { path: "./platform/data/locales/pl/test.ftl", source: "test-key = pl value" }, + ]; + let source = L10nFileSource.createMock("platform", "", ["en-US", "pl"], "./platform/data/locales/{locale}/", fs); + l10nReg.registerSources([source]); + + equal(l10nReg.getSourceNames().length, 1); + equal(l10nReg.hasSource("platform"), true); + + + // returns correct contexts for [en-US, pl] + + let bundles = l10nReg.generateBundlesSync(["en-US", "pl"], ["test.ftl", "missing-in-en-US.ftl"]); + let bundle0 = (await bundles.next()).value; + + equal(bundle0.locales[0], "pl"); + equal(bundle0.hasMessage("test-key"), true); + equal(bundle0.hasMessage("missing-key"), true); + + let msg0 = bundle0.getMessage("test-key"); + equal(bundle0.formatPattern(msg0.value), "pl value"); + + let msg1 = bundle0.getMessage("missing-key"); + equal(bundle0.formatPattern(msg1.value), "pl value"); + + equal((await bundles.next()).done, true); + + + // returns correct contexts for [pl, en-US] + + bundles = l10nReg.generateBundlesSync(["pl", "en-US"], ["test.ftl", {path: "missing-in-en-US.ftl", optional: false}]); + bundle0 = (await bundles.next()).value; + + equal(bundle0.locales[0], "pl"); + equal(bundle0.hasMessage("test-key"), true); + + msg0 = bundle0.getMessage("test-key"); + equal(bundle0.formatPattern(msg0.value), "pl value"); + + msg1 = bundle0.getMessage("missing-key"); + equal(bundle0.formatPattern(msg1.value), "pl value"); + + equal((await bundles.next()).done, true); + + // cleanup + l10nReg.clearSources(); +}); + +/** + * This test verifies that when an optional resource is missing, we continue + * to produce a bundle for that locale. The bundle will have missing entries + * with regard to the missing optional resource. + */ +add_task(async function test_missing_optional_resource() { + const fs = [ + { path: "./platform/data/locales/en-US/test.ftl", source: "test-key = en-US value" }, + { path: "./platform/data/locales/pl/missing-in-en-US.ftl", source: "missing-key = pl value" }, + { path: "./platform/data/locales/pl/test.ftl", source: "test-key = pl value" }, + ]; + let source = L10nFileSource.createMock("platform", "", ["en-US", "pl"], "./platform/data/locales/{locale}/", fs); + l10nReg.registerSources([source]); + + equal(l10nReg.getSourceNames().length, 1); + equal(l10nReg.hasSource("platform"), true); + + + // returns correct contexts for [en-US, pl] + + let bundles = l10nReg.generateBundlesSync(["en-US", "pl"], ["test.ftl", { path: "missing-in-en-US.ftl", optional: true }]); + let bundle0 = (await bundles.next()).value; + + equal(bundle0.locales[0], "en-US"); + equal(bundle0.hasMessage("test-key"), true); + equal(bundle0.hasMessage("missing-key"), false); + + let msg0 = bundle0.getMessage("test-key"); + equal(bundle0.formatPattern(msg0.value), "en-US value"); + + equal(bundle0.getMessage("missing-key"), null); + + let bundle1 = (await bundles.next()).value; + + equal(bundle1.locales[0], "pl"); + equal(bundle1.hasMessage("test-key"), true); + equal(bundle1.hasMessage("missing-key"), true); + + msg0 = bundle1.getMessage("test-key"); + equal(bundle1.formatPattern(msg0.value), "pl value"); + + msg1 = bundle1.getMessage("missing-key"); + equal(bundle1.formatPattern(msg1.value), "pl value"); + + equal((await bundles.next()).done, true); + + // returns correct contexts for [pl, en-US] + + bundles = l10nReg.generateBundlesSync(["pl", "en-US"], ["test.ftl", { path: "missing-in-en-US.ftl", optional: true }]); + bundle0 = (await bundles.next()).value; + + equal(bundle0.locales[0], "pl"); + equal(bundle0.hasMessage("test-key"), true); + equal(bundle0.hasMessage("missing-key"), true); + + msg0 = bundle0.getMessage("test-key"); + equal(bundle0.formatPattern(msg0.value), "pl value"); + + msg1 = bundle0.getMessage("missing-key"); + equal(bundle0.formatPattern(msg1.value), "pl value"); + + bundle1 = (await bundles.next()).value; + + equal(bundle1.locales[0], "en-US"); + equal(bundle1.hasMessage("test-key"), true); + equal(bundle1.hasMessage("missing-key"), false); + + msg0 = bundle1.getMessage("test-key"); + equal(bundle1.formatPattern(msg0.value), "en-US value"); + + equal(bundle1.getMessage("missing-key"), null); + + // cleanup + l10nReg.clearSources(); +}); -- cgit v1.2.3