test_l10nregistry_sync.js (17535B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 const {setTimeout} = ChromeUtils.importESModule("resource://gre/modules/Timer.sys.mjs"); 5 6 const l10nReg = new L10nRegistry(); 7 8 add_task(function test_methods_presence() { 9 equal(typeof l10nReg.generateBundles, "function"); 10 equal(typeof l10nReg.generateBundlesSync, "function"); 11 equal(typeof l10nReg.getAvailableLocales, "function"); 12 equal(typeof l10nReg.registerSources, "function"); 13 equal(typeof l10nReg.removeSources, "function"); 14 equal(typeof l10nReg.updateSources, "function"); 15 }); 16 17 /** 18 * Test that passing empty resourceIds list works. 19 */ 20 add_task(function test_empty_resourceids() { 21 const fs = []; 22 23 const source = L10nFileSource.createMock("test", "", ["en-US"], "/localization/{locale}", fs); 24 l10nReg.registerSources([source]); 25 26 const bundles = l10nReg.generateBundlesSync(["en-US"], []); 27 28 const done = (bundles.next()).done; 29 30 equal(done, true); 31 32 // cleanup 33 l10nReg.clearSources(); 34 }); 35 36 /** 37 * Test that passing empty sources list works. 38 */ 39 add_task(function test_empty_sources() { 40 const fs = []; 41 const bundles = l10nReg.generateBundlesSync(["en-US"], fs); 42 43 const done = (bundles.next()).done; 44 45 equal(done, true); 46 47 // cleanup 48 l10nReg.clearSources(); 49 }); 50 51 /** 52 * This test tests generation of a proper context for a single 53 * source scenario 54 */ 55 add_task(function test_methods_calling() { 56 const fs = [ 57 { path: "/localization/en-US/browser/menu.ftl", source: "key = Value" } 58 ]; 59 const source = L10nFileSource.createMock("test", "", ["en-US"], "/localization/{locale}", fs); 60 l10nReg.registerSources([source]); 61 62 const bundles = l10nReg.generateBundlesSync(["en-US"], ["/browser/menu.ftl"]); 63 64 const bundle = (bundles.next()).value; 65 66 equal(bundle.hasMessage("key"), true); 67 68 // cleanup 69 l10nReg.clearSources(); 70 }); 71 72 /** 73 * This test verifies that the public methods return expected values 74 * for the single source scenario 75 */ 76 add_task(function test_has_one_source() { 77 const fs = [ 78 {path: "./app/data/locales/en-US/test.ftl", source: "key = value en-US"} 79 ]; 80 let oneSource = L10nFileSource.createMock("app", "", ["en-US"], "./app/data/locales/{locale}/", fs); 81 l10nReg.registerSources([oneSource]); 82 83 84 // has one source 85 86 equal(l10nReg.getSourceNames().length, 1); 87 equal(l10nReg.hasSource("app"), true); 88 89 90 // returns a single context 91 92 let bundles = l10nReg.generateBundlesSync(["en-US"], ["test.ftl"]); 93 let bundle0 = (bundles.next()).value; 94 equal(bundle0.hasMessage("key"), true); 95 96 equal((bundles.next()).done, true); 97 98 99 // returns no contexts for missing locale 100 101 bundles = l10nReg.generateBundlesSync(["pl"], ["test.ftl"]); 102 103 equal((bundles.next()).done, true); 104 105 // cleanup 106 l10nReg.clearSources(); 107 }); 108 109 /** 110 * This test verifies that public methods return expected values 111 * for the dual source scenario. 112 */ 113 add_task(function test_has_two_sources() { 114 const fs = [ 115 { path: "./platform/data/locales/en-US/test.ftl", source: "key = platform value" }, 116 { path: "./app/data/locales/pl/test.ftl", source: "key = app value" } 117 ]; 118 let oneSource = L10nFileSource.createMock("platform", "", ["en-US"], "./platform/data/locales/{locale}/", fs); 119 let secondSource = L10nFileSource.createMock("app", "", ["pl"], "./app/data/locales/{locale}/", fs); 120 l10nReg.registerSources([oneSource, secondSource]); 121 122 // has two sources 123 124 equal(l10nReg.getSourceNames().length, 2); 125 equal(l10nReg.hasSource("app"), true); 126 equal(l10nReg.hasSource("platform"), true); 127 128 129 // returns correct contexts for en-US 130 131 let bundles = l10nReg.generateBundlesSync(["en-US"], ["test.ftl"]); 132 let bundle0 = (bundles.next()).value; 133 134 equal(bundle0.hasMessage("key"), true); 135 let msg = bundle0.getMessage("key"); 136 equal(bundle0.formatPattern(msg.value), "platform value"); 137 138 equal((bundles.next()).done, true); 139 140 141 // returns correct contexts for [pl, en-US] 142 143 bundles = l10nReg.generateBundlesSync(["pl", "en-US"], ["test.ftl"]); 144 bundle0 = (bundles.next()).value; 145 equal(bundle0.locales[0], "pl"); 146 equal(bundle0.hasMessage("key"), true); 147 let msg0 = bundle0.getMessage("key"); 148 equal(bundle0.formatPattern(msg0.value), "app value"); 149 150 let bundle1 = (bundles.next()).value; 151 equal(bundle1.locales[0], "en-US"); 152 equal(bundle1.hasMessage("key"), true); 153 let msg1 = bundle1.getMessage("key"); 154 equal(bundle1.formatPattern(msg1.value), "platform value"); 155 156 equal((bundles.next()).done, true); 157 158 // cleanup 159 l10nReg.clearSources(); 160 }); 161 162 /** 163 * This test checks if the correct order of contexts is used for 164 * scenarios where a new file source is added on top of the default one. 165 */ 166 add_task(function test_override() { 167 const fs = [ 168 { path: "/app/data/locales/pl/test.ftl", source: "key = value" }, 169 { path: "/data/locales/pl/test.ftl", source: "key = addon value"}, 170 ]; 171 let fileSource = L10nFileSource.createMock("app", "", ["pl"], "/app/data/locales/{locale}/", fs); 172 let oneSource = L10nFileSource.createMock("langpack-pl", "", ["pl"], "/data/locales/{locale}/", fs); 173 l10nReg.registerSources([fileSource, oneSource]); 174 175 equal(l10nReg.getSourceNames().length, 2); 176 equal(l10nReg.hasSource("langpack-pl"), true); 177 178 let bundles = l10nReg.generateBundlesSync(["pl"], ["test.ftl"]); 179 let bundle0 = (bundles.next()).value; 180 equal(bundle0.locales[0], "pl"); 181 equal(bundle0.hasMessage("key"), true); 182 let msg0 = bundle0.getMessage("key"); 183 equal(bundle0.formatPattern(msg0.value), "addon value"); 184 185 let bundle1 = (bundles.next()).value; 186 equal(bundle1.locales[0], "pl"); 187 equal(bundle1.hasMessage("key"), true); 188 let msg1 = bundle1.getMessage("key"); 189 equal(bundle1.formatPattern(msg1.value), "value"); 190 191 equal((bundles.next()).done, true); 192 193 // cleanup 194 l10nReg.clearSources(); 195 }); 196 197 /** 198 * This test verifies that new contexts are returned 199 * after source update. 200 */ 201 add_task(function test_updating() { 202 const fs = [ 203 { path: "/data/locales/pl/test.ftl", source: "key = value" } 204 ]; 205 let oneSource = L10nFileSource.createMock("langpack-pl", "", ["pl"], "/data/locales/{locale}/", fs); 206 l10nReg.registerSources([oneSource]); 207 208 let bundles = l10nReg.generateBundlesSync(["pl"], ["test.ftl"]); 209 let bundle0 = (bundles.next()).value; 210 equal(bundle0.locales[0], "pl"); 211 equal(bundle0.hasMessage("key"), true); 212 let msg0 = bundle0.getMessage("key"); 213 equal(bundle0.formatPattern(msg0.value), "value"); 214 215 216 const newSource = L10nFileSource.createMock("langpack-pl", "", ["pl"], "/data/locales/{locale}/", [ 217 { path: "/data/locales/pl/test.ftl", source: "key = new value" } 218 ]); 219 l10nReg.updateSources([newSource]); 220 221 equal(l10nReg.getSourceNames().length, 1); 222 bundles = l10nReg.generateBundlesSync(["pl"], ["test.ftl"]); 223 bundle0 = (bundles.next()).value; 224 msg0 = bundle0.getMessage("key"); 225 equal(bundle0.formatPattern(msg0.value), "new value"); 226 227 // cleanup 228 l10nReg.clearSources(); 229 }); 230 231 /** 232 * This test verifies that generated contexts return correct values 233 * after sources are being removed. 234 */ 235 add_task(function test_removing() { 236 const fs = [ 237 { path: "/app/data/locales/pl/test.ftl", source: "key = value" }, 238 { path: "/data/locales/pl/test.ftl", source: "key = addon value" }, 239 ]; 240 241 let fileSource = L10nFileSource.createMock("app", "", ["pl"], "/app/data/locales/{locale}/", fs); 242 let oneSource = L10nFileSource.createMock("langpack-pl", "", ["pl"], "/data/locales/{locale}/", fs); 243 l10nReg.registerSources([fileSource, oneSource]); 244 245 equal(l10nReg.getSourceNames().length, 2); 246 equal(l10nReg.hasSource("langpack-pl"), true); 247 248 let bundles = l10nReg.generateBundlesSync(["pl"], ["test.ftl"]); 249 let bundle0 = (bundles.next()).value; 250 equal(bundle0.locales[0], "pl"); 251 equal(bundle0.hasMessage("key"), true); 252 let msg0 = bundle0.getMessage("key"); 253 equal(bundle0.formatPattern(msg0.value), "addon value"); 254 255 let bundle1 = (bundles.next()).value; 256 equal(bundle1.locales[0], "pl"); 257 equal(bundle1.hasMessage("key"), true); 258 let msg1 = bundle1.getMessage("key"); 259 equal(bundle1.formatPattern(msg1.value), "value"); 260 261 equal((bundles.next()).done, true); 262 263 // Remove langpack 264 265 l10nReg.removeSources(["langpack-pl"]); 266 267 equal(l10nReg.getSourceNames().length, 1); 268 equal(l10nReg.hasSource("langpack-pl"), false); 269 270 bundles = l10nReg.generateBundlesSync(["pl"], ["test.ftl"]); 271 bundle0 = (bundles.next()).value; 272 equal(bundle0.locales[0], "pl"); 273 equal(bundle0.hasMessage("key"), true); 274 msg0 = bundle0.getMessage("key"); 275 equal(bundle0.formatPattern(msg0.value), "value"); 276 277 equal((bundles.next()).done, true); 278 279 // Remove app source 280 281 l10nReg.removeSources(["app"]); 282 283 equal(l10nReg.getSourceNames().length, 0); 284 285 bundles = l10nReg.generateBundlesSync(["pl"], ["test.ftl"]); 286 equal((bundles.next()).done, true); 287 288 // cleanup 289 l10nReg.clearSources(); 290 }); 291 292 /** 293 * This test verifies that the logic works correctly when there's a missing 294 * file in the FileSource scenario. 295 */ 296 add_task(function test_missing_file() { 297 const fs = [ 298 { path: "./app/data/locales/en-US/test.ftl", source: "key = value en-US" }, 299 { path: "./platform/data/locales/en-US/test.ftl", source: "key = value en-US" }, 300 { path: "./platform/data/locales/en-US/test2.ftl", source: "key2 = value2 en-US" }, 301 ]; 302 let oneSource = L10nFileSource.createMock("app", "", ["en-US"], "./app/data/locales/{locale}/", fs); 303 let twoSource = L10nFileSource.createMock("platform", "", ["en-US"], "./platform/data/locales/{locale}/", fs); 304 l10nReg.registerSources([oneSource, twoSource]); 305 306 // has two sources 307 308 equal(l10nReg.getSourceNames().length, 2); 309 equal(l10nReg.hasSource("app"), true); 310 equal(l10nReg.hasSource("platform"), true); 311 312 313 // returns a single context 314 315 let bundles = l10nReg.generateBundlesSync(["en-US"], ["test.ftl", "test2.ftl"]); 316 317 // First permutation: 318 // [platform, platform] - both present 319 let bundle1 = (bundles.next()); 320 equal(bundle1.value.hasMessage("key"), true); 321 322 // Second permutation skipped: 323 // [platform, app] - second missing 324 // Third permutation: 325 // [app, platform] - both present 326 let bundle2 = (bundles.next()); 327 equal(bundle2.value.hasMessage("key"), true); 328 329 // Fourth permutation skipped: 330 // [app, app] - second missing 331 equal((bundles.next()).done, true); 332 333 // cleanup 334 l10nReg.clearSources(); 335 }); 336 337 /** 338 * This test verifies that we handle correctly a scenario where a source 339 * is being removed while the iterator operates. 340 */ 341 add_task(function test_remove_source_mid_iter_cycle() { 342 const fs = [ 343 { path: "./platform/data/locales/en-US/test.ftl", source: "key = platform value" }, 344 { path: "./app/data/locales/pl/test.ftl", source: "key = app value" }, 345 ]; 346 let oneSource = L10nFileSource.createMock("platform", "", ["en-US"], "./platform/data/locales/{locale}/", fs); 347 let secondSource = L10nFileSource.createMock("app", "", ["pl"], "./app/data/locales/{locale}/", fs); 348 l10nReg.registerSources([oneSource, secondSource]); 349 350 let bundles = l10nReg.generateBundlesSync(["en-US", "pl"], ["test.ftl"]); 351 352 let bundle0 = bundles.next(); 353 354 l10nReg.removeSources(["app"]); 355 356 equal((bundles.next()).done, true); 357 358 // cleanup 359 l10nReg.clearSources(); 360 }); 361 362 add_task(async function test_metasources() { 363 let fs = [ 364 { path: "/localization/en-US/browser/menu1.ftl", source: "key1 = Value" }, 365 { path: "/localization/en-US/browser/menu2.ftl", source: "key2 = Value" }, 366 { path: "/localization/en-US/browser/menu3.ftl", source: "key3 = Value" }, 367 { path: "/localization/en-US/browser/menu4.ftl", source: "key4 = Value" }, 368 { path: "/localization/en-US/browser/menu5.ftl", source: "key5 = Value" }, 369 { path: "/localization/en-US/browser/menu6.ftl", source: "key6 = Value" }, 370 { path: "/localization/en-US/browser/menu7.ftl", source: "key7 = Value" }, 371 { path: "/localization/en-US/browser/menu8.ftl", source: "key8 = Value" }, 372 ]; 373 374 const browser = L10nFileSource.createMock("browser", "app", ["en-US"], "/localization/{locale}", fs); 375 const toolkit = L10nFileSource.createMock("toolkit", "app", ["en-US"], "/localization/{locale}", fs); 376 const browser2 = L10nFileSource.createMock("browser2", "langpack", ["en-US"], "/localization/{locale}", fs); 377 const toolkit2 = L10nFileSource.createMock("toolkit2", "langpack", ["en-US"], "/localization/{locale}", fs); 378 l10nReg.registerSources([toolkit, browser, toolkit2, browser2]); 379 380 let res = [ 381 "/browser/menu1.ftl", 382 "/browser/menu2.ftl", 383 "/browser/menu3.ftl", 384 "/browser/menu4.ftl", 385 "/browser/menu5.ftl", 386 "/browser/menu6.ftl", 387 "/browser/menu7.ftl", 388 {path: "/browser/menu8.ftl", optional: false}, 389 ]; 390 391 const bundles = l10nReg.generateBundlesSync(["en-US"], res); 392 393 let nbundles = 0; 394 while (!bundles.next().done) { 395 nbundles += 1; 396 } 397 398 // If metasources are working properly, we'll generate 2^8 = 256 bundles for 399 // each metasource giving 512 bundles in total. Otherwise, we generate 400 // 4^8 = 65536 bundles. 401 equal(nbundles, 512); 402 403 // cleanup 404 l10nReg.clearSources(); 405 }); 406 407 /** 408 * This test verifies that when a required resource is missing for a locale, 409 * we do not produce a bundle for that locale. 410 */ 411 add_task(function test_missing_required_resource() { 412 const fs = [ 413 { path: "./platform/data/locales/en-US/test.ftl", source: "test-key = en-US value" }, 414 { path: "./platform/data/locales/pl/missing-in-en-US.ftl", source: "missing-key = pl value" }, 415 { path: "./platform/data/locales/pl/test.ftl", source: "test-key = pl value" }, 416 ]; 417 let source = L10nFileSource.createMock("platform", "", ["en-US", "pl"], "./platform/data/locales/{locale}/", fs); 418 l10nReg.registerSources([source]); 419 420 equal(l10nReg.getSourceNames().length, 1); 421 equal(l10nReg.hasSource("platform"), true); 422 423 424 // returns correct contexts for [en-US, pl] 425 426 let bundles = l10nReg.generateBundlesSync(["en-US", "pl"], ["test.ftl", "missing-in-en-US.ftl"]); 427 let bundle0 = (bundles.next()).value; 428 429 equal(bundle0.locales[0], "pl"); 430 equal(bundle0.hasMessage("test-key"), true); 431 equal(bundle0.hasMessage("missing-key"), true); 432 433 let msg0 = bundle0.getMessage("test-key"); 434 equal(bundle0.formatPattern(msg0.value), "pl value"); 435 436 let msg1 = bundle0.getMessage("missing-key"); 437 equal(bundle0.formatPattern(msg1.value), "pl value"); 438 439 equal((bundles.next()).done, true); 440 441 442 // returns correct contexts for [pl, en-US] 443 444 bundles = l10nReg.generateBundlesSync(["pl", "en-US"], ["test.ftl", {path: "missing-in-en-US.ftl", optional: false}]); 445 bundle0 = (bundles.next()).value; 446 447 equal(bundle0.locales[0], "pl"); 448 equal(bundle0.hasMessage("test-key"), true); 449 450 msg0 = bundle0.getMessage("test-key"); 451 equal(bundle0.formatPattern(msg0.value), "pl value"); 452 453 msg1 = bundle0.getMessage("missing-key"); 454 equal(bundle0.formatPattern(msg1.value), "pl value"); 455 456 equal((bundles.next()).done, true); 457 458 // cleanup 459 l10nReg.clearSources(); 460 }); 461 462 /** 463 * This test verifies that when an optional resource is missing, we continue 464 * to produce a bundle for that locale. The bundle will have missing entries 465 * with regard to the missing optional resource. 466 */ 467 add_task(function test_missing_optional_resource() { 468 const fs = [ 469 { path: "./platform/data/locales/en-US/test.ftl", source: "test-key = en-US value" }, 470 { path: "./platform/data/locales/pl/missing-in-en-US.ftl", source: "missing-key = pl value" }, 471 { path: "./platform/data/locales/pl/test.ftl", source: "test-key = pl value" }, 472 ]; 473 let source = L10nFileSource.createMock("platform", "", ["en-US", "pl"], "./platform/data/locales/{locale}/", fs); 474 l10nReg.registerSources([source]); 475 476 equal(l10nReg.getSourceNames().length, 1); 477 equal(l10nReg.hasSource("platform"), true); 478 479 480 // returns correct contexts for [en-US, pl] 481 482 let bundles = l10nReg.generateBundlesSync(["en-US", "pl"], ["test.ftl", { path: "missing-in-en-US.ftl", optional: true }]); 483 let bundle0 = (bundles.next()).value; 484 485 equal(bundle0.locales[0], "en-US"); 486 equal(bundle0.hasMessage("test-key"), true); 487 equal(bundle0.hasMessage("missing-key"), false); 488 489 let msg0 = bundle0.getMessage("test-key"); 490 equal(bundle0.formatPattern(msg0.value), "en-US value"); 491 492 equal(bundle0.getMessage("missing-key"), null); 493 494 let bundle1 = (bundles.next()).value; 495 496 equal(bundle1.locales[0], "pl"); 497 equal(bundle1.hasMessage("test-key"), true); 498 equal(bundle1.hasMessage("missing-key"), true); 499 500 msg0 = bundle1.getMessage("test-key"); 501 equal(bundle1.formatPattern(msg0.value), "pl value"); 502 503 msg1 = bundle1.getMessage("missing-key"); 504 equal(bundle1.formatPattern(msg1.value), "pl value"); 505 506 equal((bundles.next()).done, true); 507 508 // returns correct contexts for [pl, en-US] 509 510 bundles = l10nReg.generateBundlesSync(["pl", "en-US"], ["test.ftl", { path: "missing-in-en-US.ftl", optional: true }]); 511 bundle0 = (bundles.next()).value; 512 513 equal(bundle0.locales[0], "pl"); 514 equal(bundle0.hasMessage("test-key"), true); 515 equal(bundle0.hasMessage("missing-key"), true); 516 517 msg0 = bundle0.getMessage("test-key"); 518 equal(bundle0.formatPattern(msg0.value), "pl value"); 519 520 msg1 = bundle0.getMessage("missing-key"); 521 equal(bundle0.formatPattern(msg1.value), "pl value"); 522 523 bundle1 = (bundles.next()).value; 524 525 equal(bundle1.locales[0], "en-US"); 526 equal(bundle1.hasMessage("test-key"), true); 527 equal(bundle1.hasMessage("missing-key"), false); 528 529 msg0 = bundle1.getMessage("test-key"); 530 equal(bundle1.formatPattern(msg0.value), "en-US value"); 531 532 equal(bundle1.getMessage("missing-key"), null); 533 534 // cleanup 535 l10nReg.clearSources(); 536 });