diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /browser/extensions/formautofill/test/unit/test_addressRecords.js | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | browser/extensions/formautofill/test/unit/test_addressRecords.js | 858 |
1 files changed, 858 insertions, 0 deletions
diff --git a/browser/extensions/formautofill/test/unit/test_addressRecords.js b/browser/extensions/formautofill/test/unit/test_addressRecords.js new file mode 100644 index 0000000000..53db04ee38 --- /dev/null +++ b/browser/extensions/formautofill/test/unit/test_addressRecords.js @@ -0,0 +1,858 @@ +/** + * Tests FormAutofillStorage object with addresses records. + */ + +"use strict"; + +const TEST_STORE_FILE_NAME = "test-profile.json"; +const COLLECTION_NAME = "addresses"; + +const TEST_ADDRESS_1 = { + "given-name": "Timothy", + "additional-name": "John", + "family-name": "Berners-Lee", + organization: "World Wide Web Consortium", + "street-address": "32 Vassar Street\nMIT Room 32-G524", + "address-level2": "Cambridge", + "address-level1": "MA", + "postal-code": "02139", + country: "US", + tel: "+16172535702", + email: "timbl@w3.org", + "unknown-1": "an unknown field from another client", +}; + +const TEST_ADDRESS_2 = { + "street-address": "Some Address", + country: "US", +}; + +const TEST_ADDRESS_3 = { + "given-name": "Timothy", + "family-name": "Berners-Lee", + "street-address": "Other Address", + "postal-code": "12345", +}; + +const TEST_ADDRESS_4 = { + "given-name": "Timothy", + "additional-name": "John", + "family-name": "Berners-Lee", + organization: "World Wide Web Consortium", +}; + +const TEST_ADDRESS_WITH_EMPTY_FIELD = { + name: "Tim Berners", + "street-address": "", +}; + +const TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD = { + name: "", + "address-line1": "", + "address-line2": "", + "address-line3": "", + "country-name": "", + "tel-country-code": "", + "tel-national": "", + "tel-area-code": "", + "tel-local": "", + "tel-local-prefix": "", + "tel-local-suffix": "", + email: "timbl@w3.org", +}; + +const TEST_ADDRESS_WITH_INVALID_FIELD = { + "street-address": "Another Address", + email: { email: "invalidemail" }, +}; + +const TEST_ADDRESS_EMPTY_AFTER_NORMALIZE = { + country: "XXXXXX", +}; + +const TEST_ADDRESS_EMPTY_AFTER_UPDATE_ADDRESS_2 = { + "street-address": "", + country: "XXXXXX", +}; + +const MERGE_TESTCASES = [ + { + description: "Merge a superset", + addressInStorage: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + "unknown-1": "an unknown field from another client", + }, + addressToMerge: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + country: "US", + "unknown-1": "an unknown field from another client", + }, + expectedAddress: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + country: "US", + "unknown-1": "an unknown field from another client", + }, + }, + { + description: "Loose merge a subset", + addressInStorage: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + country: "US", + }, + addressToMerge: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + }, + expectedAddress: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + country: "US", + }, + noNeedToUpdate: true, + }, + { + description: "Strict merge a subset without empty string", + addressInStorage: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + country: "US", + }, + addressToMerge: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + }, + expectedAddress: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + country: "US", + }, + strict: true, + noNeedToUpdate: true, + }, + { + description: "Merge an address with partial overlaps", + addressInStorage: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + }, + addressToMerge: { + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + country: "US", + }, + expectedAddress: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + country: "US", + }, + }, + { + description: + "Merge an address with multi-line street-address in storage and single-line incoming one", + addressInStorage: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue\nLine2", + tel: "+16509030800", + }, + addressToMerge: { + "street-address": "331 E. Evelyn Avenue Line2", + tel: "+16509030800", + country: "US", + }, + expectedAddress: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue\nLine2", + tel: "+16509030800", + country: "US", + }, + }, + { + description: + "Merge an address with 3-line street-address in storage and 2-line incoming one", + addressInStorage: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue\nLine2\nLine3", + tel: "+16509030800", + }, + addressToMerge: { + "street-address": "331 E. Evelyn Avenue\nLine2 Line3", + tel: "+16509030800", + country: "US", + }, + expectedAddress: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue\nLine2\nLine3", + tel: "+16509030800", + country: "US", + }, + }, + { + description: + "Merge an address with single-line street-address in storage and multi-line incoming one", + addressInStorage: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue Line2", + tel: "+16509030800", + }, + addressToMerge: { + "street-address": "331 E. Evelyn Avenue\nLine2", + tel: "+16509030800", + country: "US", + }, + expectedAddress: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue\nLine2", + tel: "+16509030800", + country: "US", + }, + }, + { + description: + "Merge an address with 2-line street-address in storage and 3-line incoming one", + addressInStorage: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue\nLine2 Line3", + tel: "+16509030800", + }, + addressToMerge: { + "street-address": "331 E. Evelyn Avenue\nLine2\nLine3", + tel: "+16509030800", + country: "US", + }, + expectedAddress: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue\nLine2\nLine3", + tel: "+16509030800", + country: "US", + }, + }, + { + description: "Merge an address with the same amount of lines", + addressInStorage: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue\nLine2\nLine3", + tel: "+16509030800", + }, + addressToMerge: { + "street-address": "331 E. Evelyn\nAvenue Line2\nLine3", + tel: "+16509030800", + country: "US", + }, + expectedAddress: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue\nLine2\nLine3", + tel: "+16509030800", + country: "US", + }, + }, + { + description: + "Merge an address with superfluous external and internal whitespace in the street-address", + addressInStorage: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue\nLine2\nLine3", + tel: "+16509030800", + }, + addressToMerge: { + "street-address": " 331 E. Evelyn\n Avenue Line2\n Line3 ", + country: "US", + }, + expectedAddress: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue\nLine2\nLine3", + tel: "+16509030800", + country: "US", + }, + }, + { + description: "Merge an address with collapsed whitespace", + addressInStorage: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + }, + addressToMerge: { + "street-address": "331 E.Evelyn Avenue", + country: "US", + }, + expectedAddress: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + country: "US", + }, + }, + { + description: "Merge an address with punctuation and mIxEd-cAsE", + addressInStorage: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + }, + addressToMerge: { + "street-address": "331.e.EVELYN AVENUE", + country: "US", + }, + expectedAddress: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Avenue", + tel: "+16509030800", + country: "US", + }, + }, + { + description: "Merge an address with accent characters", + addressInStorage: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Straße", + tel: "+16509030800", + }, + addressToMerge: { + "street-address": "331.e.EVELYN Strasse", + country: "US", + }, + expectedAddress: { + "given-name": "Timothy", + "street-address": "331 E. Evelyn Straße", + tel: "+16509030800", + country: "US", + }, + }, + { + description: "Merge an address with a mIxEd-cAsE name", + addressInStorage: { + "given-name": "Timothy", + tel: "+16509030800", + }, + addressToMerge: { + "given-name": "TIMOTHY", + tel: "+16509030800", + country: "US", + }, + expectedAddress: { + "given-name": "Timothy", + tel: "+16509030800", + country: "US", + }, + }, +]; + +ChromeUtils.defineESModuleGetters(this, { + Preferences: "resource://gre/modules/Preferences.sys.mjs", +}); + +let do_check_record_matches = (recordWithMeta, record) => { + for (let key in record) { + Assert.equal(recordWithMeta[key], record[key]); + } +}; + +add_task(async function test_initialize() { + let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME); + + Assert.equal(profileStorage._store.data.version, 1); + Assert.equal(profileStorage._store.data.addresses.length, 0); + + let data = profileStorage._store.data; + Assert.deepEqual(data.addresses, []); + + await profileStorage._saveImmediately(); + + profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME); + + Assert.deepEqual(profileStorage._store.data, data); + for (let { _sync } of profileStorage._store.data.addresses) { + Assert.ok(_sync); + Assert.equal(_sync.changeCounter, 1); + } +}); + +add_task(async function test_getAll() { + let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, [ + TEST_ADDRESS_1, + TEST_ADDRESS_2, + ]); + + let addresses = await profileStorage.addresses.getAll(); + + Assert.equal(addresses.length, 2); + do_check_record_matches(addresses[0], TEST_ADDRESS_1); + do_check_record_matches(addresses[1], TEST_ADDRESS_2); + + // Check computed fields. + Assert.equal(addresses[0].name, "Timothy John Berners-Lee"); + Assert.equal(addresses[0]["address-line1"], "32 Vassar Street"); + Assert.equal(addresses[0]["address-line2"], "MIT Room 32-G524"); + + // Test with rawData set. + addresses = await profileStorage.addresses.getAll({ rawData: true }); + Assert.equal(addresses[0].name, undefined); + Assert.equal(addresses[0]["address-line1"], undefined); + Assert.equal(addresses[0]["address-line2"], undefined); + + // Modifying output shouldn't affect the storage. + addresses[0].organization = "test"; + do_check_record_matches( + (await profileStorage.addresses.getAll())[0], + TEST_ADDRESS_1 + ); +}); + +add_task(async function test_get() { + let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, [ + TEST_ADDRESS_1, + TEST_ADDRESS_2, + ]); + + let addresses = await profileStorage.addresses.getAll(); + let guid = addresses[0].guid; + + let address = await profileStorage.addresses.get(guid); + do_check_record_matches(address, TEST_ADDRESS_1); + + // Test with rawData set. + address = await profileStorage.addresses.get(guid, { rawData: true }); + Assert.equal(address.name, undefined); + Assert.equal(address["address-line1"], undefined); + Assert.equal(address["address-line2"], undefined); + + // Modifying output shouldn't affect the storage. + address.organization = "test"; + do_check_record_matches( + await profileStorage.addresses.get(guid), + TEST_ADDRESS_1 + ); + + Assert.equal(await profileStorage.addresses.get("INVALID_GUID"), null); +}); + +add_task(async function test_add() { + let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, [ + TEST_ADDRESS_1, + TEST_ADDRESS_2, + ]); + + let addresses = await profileStorage.addresses.getAll(); + + Assert.equal(addresses.length, 2); + + do_check_record_matches(addresses[0], TEST_ADDRESS_1); + do_check_record_matches(addresses[1], TEST_ADDRESS_2); + + Assert.notEqual(addresses[0].guid, undefined); + Assert.equal(addresses[0].version, 1); + Assert.notEqual(addresses[0].timeCreated, undefined); + Assert.equal(addresses[0].timeLastModified, addresses[0].timeCreated); + Assert.equal(addresses[0].timeLastUsed, 0); + Assert.equal(addresses[0].timesUsed, 0); + + // Empty string should be deleted before saving. + await profileStorage.addresses.add(TEST_ADDRESS_WITH_EMPTY_FIELD); + let address = profileStorage.addresses._data[2]; + Assert.equal(address.name, TEST_ADDRESS_WITH_EMPTY_FIELD.name); + Assert.equal(address["street-address"], undefined); + + // Empty computed fields shouldn't cause any problem. + await profileStorage.addresses.add(TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD); + address = profileStorage.addresses._data[3]; + Assert.equal(address.email, TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD.email); + + await Assert.rejects( + profileStorage.addresses.add(TEST_ADDRESS_WITH_INVALID_FIELD), + /"email" contains invalid data type: object/ + ); + + await Assert.rejects( + profileStorage.addresses.add({}), + /Record contains no valid field\./ + ); + + await Assert.rejects( + profileStorage.addresses.add(TEST_ADDRESS_EMPTY_AFTER_NORMALIZE), + /Record contains no valid field\./ + ); +}); + +add_task(async function test_update() { + // Test assumes that when an entry is saved a second time, it's last modified date will + // be different from the first. With high values of precision reduction, we execute too + // fast for that to be true. + let timerPrecision = Preferences.get("privacy.reduceTimerPrecision"); + Preferences.set("privacy.reduceTimerPrecision", false); + + registerCleanupFunction(function () { + Preferences.set("privacy.reduceTimerPrecision", timerPrecision); + }); + + let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, [ + TEST_ADDRESS_1, + TEST_ADDRESS_2, + ]); + + let addresses = await profileStorage.addresses.getAll(); + let guid = addresses[1].guid; + // We need to cheat a little due to race conditions of Date.now() when + // we're running these tests, so we subtract one and test accordingly + // in the times Date.now() returns the same timestamp + let timeLastModified = addresses[1].timeLastModified - 1; + + let onChanged = TestUtils.topicObserved( + "formautofill-storage-changed", + (subject, data) => + data == "update" && + subject.wrappedJSObject.guid == guid && + subject.wrappedJSObject.collectionName == COLLECTION_NAME + ); + + Assert.notEqual(addresses[1].country, undefined); + + await profileStorage.addresses.update(guid, TEST_ADDRESS_3); + await onChanged; + await profileStorage._saveImmediately(); + + profileStorage.addresses.pullSyncChanges(); // force sync metadata, which we check below. + + let address = await profileStorage.addresses.get(guid, { rawData: true }); + + Assert.equal(address.country, undefined); + Assert.ok(address.timeLastModified > timeLastModified); + do_check_record_matches(address, TEST_ADDRESS_3); + Assert.equal(getSyncChangeCounter(profileStorage.addresses, guid), 1); + + // Test preserveOldProperties parameter and field with empty string. + await profileStorage.addresses.update( + guid, + TEST_ADDRESS_WITH_EMPTY_FIELD, + true + ); + await onChanged; + await profileStorage._saveImmediately(); + + profileStorage.addresses.pullSyncChanges(); // force sync metadata, which we check below. + + address = await profileStorage.addresses.get(guid, { rawData: true }); + + Assert.equal(address["given-name"], "Tim"); + Assert.equal(address["family-name"], "Berners"); + Assert.equal(address["street-address"], undefined); + Assert.equal(address["postal-code"], "12345"); + Assert.notEqual(address.timeLastModified, timeLastModified); + Assert.equal(getSyncChangeCounter(profileStorage.addresses, guid), 2); + + // Empty string should be deleted while updating. + await profileStorage.addresses.update( + profileStorage.addresses._data[0].guid, + TEST_ADDRESS_WITH_EMPTY_FIELD + ); + address = profileStorage.addresses._data[0]; + Assert.equal(address.name, TEST_ADDRESS_WITH_EMPTY_FIELD.name); + Assert.equal(address["street-address"], undefined); + Assert.equal(address[("unknown-1", "an unknown field from another client")]); + + // Empty computed fields shouldn't cause any problem. + await profileStorage.addresses.update( + profileStorage.addresses._data[0].guid, + TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD, + false + ); + address = profileStorage.addresses._data[0]; + Assert.equal(address.email, TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD.email); + await profileStorage.addresses.update( + profileStorage.addresses._data[1].guid, + TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD, + true + ); + address = profileStorage.addresses._data[1]; + Assert.equal(address.email, TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD.email); + + await Assert.rejects( + profileStorage.addresses.update("INVALID_GUID", TEST_ADDRESS_3), + /No matching record\./ + ); + + await Assert.rejects( + profileStorage.addresses.update(guid, TEST_ADDRESS_WITH_INVALID_FIELD), + /"email" contains invalid data type: object/ + ); + + await Assert.rejects( + profileStorage.addresses.update(guid, {}), + /Record contains no valid field\./ + ); + + await Assert.rejects( + profileStorage.addresses.update(guid, TEST_ADDRESS_EMPTY_AFTER_NORMALIZE), + /Record contains no valid field\./ + ); + + profileStorage.addresses.update(guid, TEST_ADDRESS_2); + await Assert.rejects( + profileStorage.addresses.update( + guid, + TEST_ADDRESS_EMPTY_AFTER_UPDATE_ADDRESS_2 + ), + /Record contains no valid field\./ + ); +}); + +add_task(async function test_notifyUsed() { + let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, [ + TEST_ADDRESS_1, + TEST_ADDRESS_2, + ]); + + let addresses = await profileStorage.addresses.getAll(); + let guid = addresses[1].guid; + let timeLastUsed = addresses[1].timeLastUsed; + let timesUsed = addresses[1].timesUsed; + + profileStorage.addresses.pullSyncChanges(); // force sync metadata, which we check below. + let changeCounter = getSyncChangeCounter(profileStorage.addresses, guid); + + let onChanged = TestUtils.topicObserved( + "formautofill-storage-changed", + (subject, data) => + data == "notifyUsed" && + subject.wrappedJSObject.guid == guid && + subject.wrappedJSObject.collectionName == COLLECTION_NAME + ); + + profileStorage.addresses.notifyUsed(guid); + await onChanged; + + let address = await profileStorage.addresses.get(guid); + + Assert.equal(address.timesUsed, timesUsed + 1); + Assert.notEqual(address.timeLastUsed, timeLastUsed); + + // Using a record should not bump its change counter. + Assert.equal( + getSyncChangeCounter(profileStorage.addresses, guid), + changeCounter + ); + + Assert.throws( + () => profileStorage.addresses.notifyUsed("INVALID_GUID"), + /No matching record\./ + ); +}); + +add_task(async function test_remove() { + let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, [ + TEST_ADDRESS_1, + TEST_ADDRESS_2, + ]); + + let addresses = await profileStorage.addresses.getAll(); + let guid = addresses[1].guid; + + let onChanged = TestUtils.topicObserved( + "formautofill-storage-changed", + (subject, data) => + data == "remove" && + subject.wrappedJSObject.guid == guid && + subject.wrappedJSObject.collectionName == COLLECTION_NAME + ); + + Assert.equal(addresses.length, 2); + + profileStorage.addresses.remove(guid); + await onChanged; + + addresses = await profileStorage.addresses.getAll(); + + Assert.equal(addresses.length, 1); + + Assert.equal(await profileStorage.addresses.get(guid), null); +}); + +MERGE_TESTCASES.forEach(testcase => { + add_task(async function test_merge() { + info("Starting testcase: " + testcase.description); + let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, [ + testcase.addressInStorage, + ]); + let addresses = await profileStorage.addresses.getAll(); + let guid = addresses[0].guid; + // We need to cheat a little due to race conditions of Date.now() when + // we're running these tests, so we subtract one and test accordingly + // in the times Date.now() returns the same timestamp + let timeLastModified = addresses[0].timeLastModified - 1; + + // Merge address and verify the guid in notifyObservers subject + let onMerged = TestUtils.topicObserved( + "formautofill-storage-changed", + (subject, data) => + data == "update" && + subject.wrappedJSObject.guid == guid && + subject.wrappedJSObject.collectionName == COLLECTION_NAME + ); + + // Force to create sync metadata. + profileStorage.addresses.pullSyncChanges(); + Assert.equal(getSyncChangeCounter(profileStorage.addresses, guid), 1); + + Assert.ok( + profileStorage.addresses.mergeIfPossible( + guid, + testcase.addressToMerge, + testcase.strict + ) + ); + if (!testcase.noNeedToUpdate) { + await onMerged; + } + + addresses = await profileStorage.addresses.getAll(); + Assert.equal(addresses.length, 1); + do_check_record_matches(addresses[0], testcase.expectedAddress); + if (testcase.noNeedToUpdate) { + // see timeLastModified for why we check -1 + Assert.equal(addresses[0].timeLastModified - 1, timeLastModified); + + // No need to bump the change counter if the data is unchanged. + Assert.equal(getSyncChangeCounter(profileStorage.addresses, guid), 1); + } else { + Assert.ok(addresses[0].timeLastModified > timeLastModified); + + // Record merging should bump the change counter. + Assert.equal(getSyncChangeCounter(profileStorage.addresses, guid), 2); + } + }); +}); + +add_task(async function test_merge_same_address() { + let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, [ + TEST_ADDRESS_1, + ]); + let addresses = await profileStorage.addresses.getAll(); + let guid = addresses[0].guid; + let timeLastModified = addresses[0].timeLastModified; + + // Force to create sync metadata. + profileStorage.addresses.pullSyncChanges(); + Assert.equal(getSyncChangeCounter(profileStorage.addresses, guid), 1); + + // Merge same address will still return true but it won't update timeLastModified. + Assert.ok(profileStorage.addresses.mergeIfPossible(guid, TEST_ADDRESS_1)); + Assert.equal(addresses[0].timeLastModified, timeLastModified); + + // ... and won't bump the change counter, either. + Assert.equal(getSyncChangeCounter(profileStorage.addresses, guid), 1); +}); + +add_task(async function test_merge_unable_merge() { + let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, [ + TEST_ADDRESS_1, + TEST_ADDRESS_2, + ]); + + let addresses = await profileStorage.addresses.getAll(); + let guid = addresses[1].guid; + + // Force to create sync metadata. + profileStorage.addresses.pullSyncChanges(); + Assert.equal(getSyncChangeCounter(profileStorage.addresses, guid), 1); + + // Unable to merge because of conflict + Assert.equal( + await profileStorage.addresses.mergeIfPossible(guid, TEST_ADDRESS_3), + false + ); + + // Unable to merge because no overlap + Assert.equal( + await profileStorage.addresses.mergeIfPossible(guid, TEST_ADDRESS_4), + false + ); + + // Unable to strict merge because subset with empty string + let subset = Object.assign({}, TEST_ADDRESS_1); + subset.organization = ""; + Assert.equal( + await profileStorage.addresses.mergeIfPossible(guid, subset, true), + false + ); + + // Shouldn't bump the change counter + Assert.equal(getSyncChangeCounter(profileStorage.addresses, guid), 1); +}); + +add_task(async function test_mergeToStorage() { + let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, [ + TEST_ADDRESS_1, + TEST_ADDRESS_2, + ]); + // Merge an address to storage + let anotherAddress = profileStorage.addresses._clone(TEST_ADDRESS_2); + await profileStorage.addresses.add(anotherAddress); + anotherAddress.email = "timbl@w3.org"; + Assert.equal( + (await profileStorage.addresses.mergeToStorage(anotherAddress)).length, + 2 + ); + + Assert.equal( + (await profileStorage.addresses.getAll())[1].email, + anotherAddress.email + ); + Assert.equal( + (await profileStorage.addresses.getAll())[2].email, + anotherAddress.email + ); + + // Empty computed fields shouldn't cause any problem. + Assert.equal( + ( + await profileStorage.addresses.mergeToStorage( + TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD + ) + ).length, + 3 + ); +}); + +add_task(async function test_mergeToStorage_strict() { + let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, [ + TEST_ADDRESS_1, + TEST_ADDRESS_2, + ]); + // Try to merge a subset with empty string + let anotherAddress = profileStorage.addresses._clone(TEST_ADDRESS_1); + anotherAddress.email = ""; + Assert.equal( + (await profileStorage.addresses.mergeToStorage(anotherAddress, true)) + .length, + 0 + ); + Assert.equal( + (await profileStorage.addresses.getAll())[0].email, + TEST_ADDRESS_1.email + ); + + // Empty computed fields shouldn't cause any problem. + Assert.equal( + ( + await profileStorage.addresses.mergeToStorage( + TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD, + true + ) + ).length, + 1 + ); +}); |