summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/addrbook/test/unit/test_vCardProperties.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/addrbook/test/unit/test_vCardProperties.js')
-rw-r--r--comm/mailnews/addrbook/test/unit/test_vCardProperties.js899
1 files changed, 899 insertions, 0 deletions
diff --git a/comm/mailnews/addrbook/test/unit/test_vCardProperties.js b/comm/mailnews/addrbook/test/unit/test_vCardProperties.js
new file mode 100644
index 0000000000..cf2c28a634
--- /dev/null
+++ b/comm/mailnews/addrbook/test/unit/test_vCardProperties.js
@@ -0,0 +1,899 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Tests of VCardProperties and VCardPropertyEntry. */
+
+var { AddrBookCard } = ChromeUtils.import(
+ "resource:///modules/AddrBookCard.jsm"
+);
+var { VCardProperties, VCardPropertyEntry } = ChromeUtils.import(
+ "resource:///modules/VCardUtils.jsm"
+);
+
+function propertyEqual(actual, expected, message) {
+ let actualAsObject = {
+ name: actual.name,
+ params: actual.params,
+ type: actual.type,
+ value: actual.value,
+ };
+ Assert.deepEqual(actualAsObject, expected, message);
+}
+
+function propertyArrayEqual(actual, expected, message) {
+ Assert.deepEqual(
+ actual.map(a => {
+ return {
+ name: a.name,
+ params: a.params,
+ type: a.type,
+ value: a.value,
+ };
+ }),
+ expected,
+ message
+ );
+}
+
+/**
+ * Tests that AddrBookCard supports vCard.
+ */
+add_task(function testAddrBookCard() {
+ let card = new AddrBookCard();
+ Assert.equal(card.supportsVCard, true, "AddrBookCard supports vCard");
+ Assert.ok(card.vCardProperties, "AddrBookCard has vCardProperties");
+ Assert.equal(card.vCardProperties.constructor.name, "VCardProperties");
+});
+
+/**
+ * Tests that nsAbCardProperty does not support vCard.
+ */
+add_task(function testABCardProperty() {
+ let card = Cc["@mozilla.org/addressbook/cardproperty;1"].createInstance(
+ Ci.nsIAbCard
+ );
+ Assert.equal(
+ card.supportsVCard,
+ false,
+ "nsAbCardProperty does not support vCard"
+ );
+ Assert.strictEqual(
+ card.vCardProperties,
+ null,
+ "nsAbCardProperty has no vCardProperties"
+ );
+});
+
+/**
+ * Tests the `clone` and `equals` functions of VCardPropertyEntry, with a
+ * simple value type.
+ */
+add_task(function testPropertyEntrySingleValue() {
+ let entry = new VCardPropertyEntry("fn", {}, "text", "Juliet");
+ let clone = entry.clone();
+
+ Assert.ok(entry.equals(entry), "original is equal to itself");
+ Assert.ok(entry.equals(clone), "original is equal to cloned object");
+ Assert.ok(clone.equals(entry), "cloned object is equal to original");
+ Assert.ok(clone.equals(clone), "cloned object is equal to itself");
+
+ Assert.equal(clone.value, entry.value, "values are identical");
+
+ let other = new VCardPropertyEntry("n", {}, "text", "Romeo");
+ Assert.ok(!entry.equals(other), "original is not equal to another object");
+ Assert.ok(!other.equals(entry), "another object is not equal to original");
+});
+
+/**
+ * Tests the `clone` and `equals` functions of VCardPropertyEntry, with a
+ * complex value type.
+ */
+add_task(function testPropertyEntryMultiValue() {
+ // A name entry for somebody named "Mr One Two Three Four Senior".
+ let entry = new VCardPropertyEntry("n", {}, "text", [
+ "Four",
+ "One",
+ ["Two", "Three"],
+ "Mr",
+ "Senior",
+ ]);
+ let clone = entry.clone();
+
+ Assert.ok(entry.equals(entry), "original is equal to itself");
+ Assert.ok(entry.equals(clone), "original is equal to cloned object");
+ Assert.ok(clone.equals(entry), "cloned object is equal to original");
+ Assert.ok(clone.equals(clone), "cloned object is equal to itself");
+
+ Assert.deepEqual(clone.value, entry.value, "values are identical");
+
+ Assert.notEqual(
+ clone.value,
+ entry.value,
+ "value arrays are separate objects"
+ );
+ Assert.notEqual(
+ clone.value[2],
+ entry.value[2],
+ "subvalue arrays are separate objects"
+ );
+
+ // A name entry for somebody named "Mr One Two Three Four Junior".
+ let other = new VCardPropertyEntry("n", {}, "text", [
+ "Four",
+ "One",
+ ["Two", "Three"],
+ "Mr",
+ "Junior",
+ ]);
+ Assert.ok(!entry.equals(other), "original is not equal to another object");
+ Assert.ok(!other.equals(entry), "another object is not equal to original");
+});
+
+/**
+ * Tests creating a VCardProperties from a vCard string,
+ * then recreating the vCard.
+ */
+add_task(function testFromToVCard() {
+ let inVCard = formatVCard`
+ BEGIN:VCARD
+ VERSION:3.0
+ FN:Mike Test
+ N:Test;Mike;;;
+ EMAIL;PREF=1:mike@test.invalid
+ NICKNAME:Testing Mike
+ CATEGORIES:testers,quality control,QA
+ END:VCARD`;
+ let properties = VCardProperties.fromVCard(inVCard);
+
+ Assert.equal(properties.entries.length, 6, "entry count");
+ propertyEqual(
+ properties.getFirstEntry("version"),
+ {
+ name: "version",
+ params: {},
+ type: "text",
+ value: "3.0",
+ },
+ "version entry"
+ );
+ propertyEqual(
+ properties.getFirstEntry("fn"),
+ {
+ name: "fn",
+ params: {},
+ type: "text",
+ value: "Mike Test",
+ },
+ "fn entry"
+ );
+ propertyEqual(
+ properties.getFirstEntry("n"),
+ {
+ name: "n",
+ params: {},
+ type: "text",
+ value: ["Test", "Mike", "", "", ""],
+ },
+ "n entry"
+ );
+ propertyEqual(
+ properties.getFirstEntry("email"),
+ {
+ name: "email",
+ params: { pref: 1 },
+ type: "text",
+ value: "mike@test.invalid",
+ },
+ "email entry"
+ );
+ propertyEqual(
+ properties.getFirstEntry("nickname"),
+ {
+ name: "nickname",
+ params: {},
+ type: "text",
+ value: "Testing Mike",
+ },
+ "multivalue entry with one value"
+ );
+ propertyEqual(
+ properties.getFirstEntry("categories"),
+ {
+ name: "categories",
+ params: {},
+ type: "text",
+ value: ["testers", "quality control", "QA"],
+ },
+ "multivalue entry with multiple values"
+ );
+
+ let outVCard = properties.toVCard();
+ Assert.equal(outVCard, inVCard, "vCard reproduction");
+});
+
+/**
+ * Tests creating a VCardProperties from a Map of old-style address book
+ * properties, then recreating the Map.
+ */
+add_task(function testFromToPropertyMap() {
+ let inProperties = [
+ ["DisplayName", "Mike Test"],
+ ["LastName", "Test"],
+ ["FirstName", "Mike"],
+ ["PrimaryEmail", "mike@test.invalid"],
+ ["Custom1", "custom one"],
+ ["Custom2", "custom two"],
+ ["Custom3", "custom three"],
+ ["Custom4", "custom four"],
+ ];
+ let properties = VCardProperties.fromPropertyMap(
+ new Map(inProperties),
+ "3.0"
+ );
+
+ Assert.equal(properties.entries.length, 8, "entry count");
+ propertyEqual(
+ properties.getFirstEntry("version"),
+ {
+ name: "version",
+ params: {},
+ type: "text",
+ value: "3.0",
+ },
+ "version entry"
+ );
+ propertyEqual(
+ properties.getFirstEntry("fn"),
+ {
+ name: "fn",
+ params: {},
+ type: "text",
+ value: "Mike Test",
+ },
+ "fn entry"
+ );
+ propertyEqual(
+ properties.getFirstEntry("n"),
+ {
+ name: "n",
+ params: {},
+ type: "text",
+ value: ["Test", "Mike", "", "", ""],
+ },
+ "n entry"
+ );
+ propertyEqual(
+ properties.getFirstEntry("email"),
+ {
+ name: "email",
+ params: { pref: 1 },
+ type: "text",
+ value: "mike@test.invalid",
+ },
+ "email entry"
+ );
+ propertyEqual(
+ properties.getFirstEntry("x-custom1"),
+ {
+ name: "x-custom1",
+ params: {},
+ type: "text",
+ value: "custom one",
+ },
+ "custom1 entry"
+ );
+ propertyEqual(
+ properties.getFirstEntry("x-custom2"),
+ {
+ name: "x-custom2",
+ params: {},
+ type: "text",
+ value: "custom two",
+ },
+ "custom2 entry"
+ );
+ propertyEqual(
+ properties.getFirstEntry("x-custom3"),
+ {
+ name: "x-custom3",
+ params: {},
+ type: "text",
+ value: "custom three",
+ },
+ "custom3 entry"
+ );
+ propertyEqual(
+ properties.getFirstEntry("x-custom4"),
+ {
+ name: "x-custom4",
+ params: {},
+ type: "text",
+ value: "custom four",
+ },
+ "custom4 entry"
+ );
+
+ let outProperties = properties.toPropertyMap();
+ Assert.equal(outProperties.size, 8, "property count");
+ for (let [key, value] of inProperties) {
+ Assert.equal(outProperties.get(key), value, `${key} property`);
+ }
+
+ // Tests that `toPropertyMap` doesn't break multi-value entries, which could
+ // happen if `toAbCard` operates on the original entry instead of a clone.
+ properties = new VCardProperties();
+ properties.addEntry(
+ new VCardPropertyEntry("org", {}, "text", ["one", "two", "three", "four"])
+ );
+ properties.toPropertyMap();
+ Assert.deepEqual(properties.getFirstValue("org"), [
+ "one",
+ "two",
+ "three",
+ "four",
+ ]);
+});
+
+/**
+ * Tests adding to and removing from VCardProperties using VCardPropertyEntry.
+ */
+add_task(function testEntryMethods() {
+ // Sanity check.
+
+ let props = new VCardProperties();
+ Assert.deepEqual(props.entries, [], "props has no entries");
+
+ // Add property entries.
+
+ // Real VCardPropertyEntry objects.
+ let charlie = new VCardPropertyEntry(
+ "email",
+ { type: "home" },
+ "text",
+ "charlie@invalid"
+ );
+ let delta = new VCardPropertyEntry(
+ "email",
+ { type: "work" },
+ "text",
+ "delta@invalid"
+ );
+
+ // Ordinary objects for Assert.deepEqual comparison. Use these objects to be
+ // sure of the values being tested.
+ let data = {
+ charlie: {
+ name: "email",
+ params: { type: "home" },
+ type: "text",
+ value: "charlie@invalid",
+ },
+ delta: {
+ name: "email",
+ params: { type: "work" },
+ type: "text",
+ value: "delta@invalid",
+ },
+ juliet: {
+ name: "email",
+ params: { type: "home" },
+ type: "text",
+ value: "juliet@invalid",
+ },
+ };
+
+ Assert.ok(props.addEntry(charlie));
+ propertyArrayEqual(
+ props.getAllEntries("email"),
+ [data.charlie],
+ "props.email has one entry"
+ );
+ Assert.deepEqual(
+ props.getAllValues("email"),
+ ["charlie@invalid"],
+ "props.email has one value"
+ );
+ Assert.equal(
+ props.getFirstValue("email"),
+ "charlie@invalid",
+ "props.email has a first value"
+ );
+ propertyArrayEqual(props.entries, [data.charlie], "props has one entry");
+
+ Assert.ok(props.addEntry(delta));
+ propertyArrayEqual(
+ props.getAllEntries("email"),
+ [data.charlie, data.delta],
+ "props.email has two entries"
+ );
+ Assert.deepEqual(
+ props.getAllValues("email"),
+ ["charlie@invalid", "delta@invalid"],
+ "props.email has two values"
+ );
+ Assert.equal(
+ props.getFirstValue("email"),
+ "charlie@invalid",
+ "props.email has a first value"
+ );
+ propertyArrayEqual(
+ props.entries,
+ [data.charlie, data.delta],
+ "props has two entries"
+ );
+
+ Assert.ok(!props.addEntry(charlie));
+ propertyArrayEqual(
+ props.entries,
+ [data.charlie, data.delta],
+ "props still has two entries"
+ );
+
+ // Update a property entry.
+
+ charlie.value = "juliet@invalid";
+ propertyArrayEqual(
+ props.getAllEntries("email"),
+ [data.juliet, data.delta],
+ "props.email has two entries"
+ );
+ Assert.deepEqual(
+ props.getAllValues("email"),
+ ["juliet@invalid", "delta@invalid"],
+ "props.email has two values"
+ );
+ Assert.equal(
+ props.getFirstValue("email"),
+ "juliet@invalid",
+ "props.email has a first value"
+ );
+ propertyArrayEqual(
+ props.entries,
+ [data.juliet, data.delta],
+ "props has two entries"
+ );
+
+ // Clone a property entry.
+
+ let juliet = charlie.clone();
+ Assert.notEqual(
+ juliet,
+ charlie,
+ "cloned VCardPropertyEntry is not the same object"
+ );
+ propertyEqual(
+ juliet,
+ data.juliet,
+ "cloned VCardPropertyEntry has the same properties"
+ );
+
+ // Delete a property entry.
+
+ Assert.ok(props.removeEntry(delta));
+ propertyArrayEqual(
+ props.getAllEntries("email"),
+ [data.juliet],
+ "props.email has one entry"
+ );
+ Assert.deepEqual(
+ props.getAllValues("email"),
+ ["juliet@invalid"],
+ "props.email has one value"
+ );
+ Assert.equal(
+ props.getFirstValue("email"),
+ "juliet@invalid",
+ "props.email has a first value"
+ );
+ propertyArrayEqual(props.entries, [data.juliet], "props has one entry");
+
+ // Delete a property entry using a clone of it.
+
+ Assert.ok(props.removeEntry(juliet));
+ propertyArrayEqual(props.entries, [], "all entries removed");
+});
+
+/**
+ * Tests adding to and removing from VCardProperties using names and values.
+ * Uses the vCard 3 default entry types.
+ */
+add_task(function testValueMethods3() {
+ let props = new VCardProperties();
+
+ // Add a value.
+
+ let first = props.addValue("tel", "1234567");
+ propertyEqual(first, {
+ name: "tel",
+ params: {},
+ type: "phone-number",
+ value: "1234567",
+ });
+ propertyArrayEqual(props.entries, [
+ { name: "tel", params: {}, type: "phone-number", value: "1234567" },
+ ]);
+
+ // Add a second value.
+
+ let second = props.addValue("tel", "2345678");
+ propertyEqual(second, {
+ name: "tel",
+ params: {},
+ type: "phone-number",
+ value: "2345678",
+ });
+ propertyArrayEqual(props.entries, [
+ { name: "tel", params: {}, type: "phone-number", value: "1234567" },
+ { name: "tel", params: {}, type: "phone-number", value: "2345678" },
+ ]);
+
+ // Add a value that already exists. The existing property should be returned.
+
+ let secondCopy = props.addValue("tel", "2345678");
+ Assert.equal(secondCopy, second);
+ propertyArrayEqual(props.entries, [
+ { name: "tel", params: {}, type: "phone-number", value: "1234567" },
+ { name: "tel", params: {}, type: "phone-number", value: "2345678" },
+ ]);
+
+ // Add a third value.
+
+ let third = props.addValue("tel", "3456789");
+ propertyEqual(third, {
+ name: "tel",
+ params: {},
+ type: "phone-number",
+ value: "3456789",
+ });
+ propertyArrayEqual(props.entries, [
+ { name: "tel", params: {}, type: "phone-number", value: "1234567" },
+ { name: "tel", params: {}, type: "phone-number", value: "2345678" },
+ { name: "tel", params: {}, type: "phone-number", value: "3456789" },
+ ]);
+
+ // Remove the second value.
+
+ props.removeValue("tel", "2345678");
+ propertyArrayEqual(props.entries, [
+ { name: "tel", params: {}, type: "phone-number", value: "1234567" },
+ { name: "tel", params: {}, type: "phone-number", value: "3456789" },
+ ]);
+
+ // Remove a value that's already been removed.
+
+ props.removeValue("tel", "2345678");
+ propertyArrayEqual(props.entries, [
+ { name: "tel", params: {}, type: "phone-number", value: "1234567" },
+ { name: "tel", params: {}, type: "phone-number", value: "3456789" },
+ ]);
+
+ // Remove a value that never existed.
+
+ props.removeValue("tel", "4567890");
+ propertyArrayEqual(props.entries, [
+ { name: "tel", params: {}, type: "phone-number", value: "1234567" },
+ { name: "tel", params: {}, type: "phone-number", value: "3456789" },
+ ]);
+
+ // Remove the first value.
+
+ props.removeValue("tel", "1234567");
+ propertyArrayEqual(props.entries, [
+ { name: "tel", params: {}, type: "phone-number", value: "3456789" },
+ ]);
+
+ // Remove the last value.
+
+ props.removeValue("tel", "3456789");
+ propertyArrayEqual(props.entries, []);
+});
+
+/**
+ * Tests adding to and removing from VCardProperties using names and values.
+ * Uses the vCard 4 default entry types.
+ */
+add_task(function testValueMethods4() {
+ let props = new VCardProperties("4.0");
+
+ // Add a value.
+
+ let first = props.addValue("tel", "tel:1234567");
+ propertyEqual(first, {
+ name: "tel",
+ params: {},
+ type: "uri",
+ value: "tel:1234567",
+ });
+ propertyArrayEqual(props.entries, [
+ { name: "version", params: {}, type: "text", value: "4.0" },
+ { name: "tel", params: {}, type: "uri", value: "tel:1234567" },
+ ]);
+
+ // Add a second value.
+
+ let second = props.addValue("tel", "tel:2345678");
+ propertyEqual(second, {
+ name: "tel",
+ params: {},
+ type: "uri",
+ value: "tel:2345678",
+ });
+ propertyArrayEqual(props.entries, [
+ { name: "version", params: {}, type: "text", value: "4.0" },
+ { name: "tel", params: {}, type: "uri", value: "tel:1234567" },
+ { name: "tel", params: {}, type: "uri", value: "tel:2345678" },
+ ]);
+
+ // Add a value that already exists. The existing property should be returned.
+
+ let secondCopy = props.addValue("tel", "tel:2345678");
+ Assert.equal(secondCopy, second);
+ propertyArrayEqual(props.entries, [
+ { name: "version", params: {}, type: "text", value: "4.0" },
+ { name: "tel", params: {}, type: "uri", value: "tel:1234567" },
+ { name: "tel", params: {}, type: "uri", value: "tel:2345678" },
+ ]);
+
+ // Add a third value.
+
+ let third = props.addValue("tel", "tel:3456789");
+ propertyEqual(third, {
+ name: "tel",
+ params: {},
+ type: "uri",
+ value: "tel:3456789",
+ });
+ propertyArrayEqual(props.entries, [
+ { name: "version", params: {}, type: "text", value: "4.0" },
+ { name: "tel", params: {}, type: "uri", value: "tel:1234567" },
+ { name: "tel", params: {}, type: "uri", value: "tel:2345678" },
+ { name: "tel", params: {}, type: "uri", value: "tel:3456789" },
+ ]);
+
+ // Remove the second value.
+
+ props.removeValue("tel", "tel:2345678");
+ propertyArrayEqual(props.entries, [
+ { name: "version", params: {}, type: "text", value: "4.0" },
+ { name: "tel", params: {}, type: "uri", value: "tel:1234567" },
+ { name: "tel", params: {}, type: "uri", value: "tel:3456789" },
+ ]);
+
+ // Remove a value that's already been removed.
+
+ props.removeValue("tel", "tel:2345678");
+ propertyArrayEqual(props.entries, [
+ { name: "version", params: {}, type: "text", value: "4.0" },
+ { name: "tel", params: {}, type: "uri", value: "tel:1234567" },
+ { name: "tel", params: {}, type: "uri", value: "tel:3456789" },
+ ]);
+
+ // Remove a value that never existed.
+
+ props.removeValue("tel", "tel:4567890");
+ propertyArrayEqual(props.entries, [
+ { name: "version", params: {}, type: "text", value: "4.0" },
+ { name: "tel", params: {}, type: "uri", value: "tel:1234567" },
+ { name: "tel", params: {}, type: "uri", value: "tel:3456789" },
+ ]);
+
+ // Remove the first value.
+
+ props.removeValue("tel", "tel:1234567");
+ propertyArrayEqual(props.entries, [
+ { name: "version", params: {}, type: "text", value: "4.0" },
+ { name: "tel", params: {}, type: "uri", value: "tel:3456789" },
+ ]);
+
+ // Remove the last value.
+
+ props.removeValue("tel", "tel:3456789");
+ propertyArrayEqual(props.entries, [
+ { name: "version", params: {}, type: "text", value: "4.0" },
+ ]);
+});
+
+/**
+ * Tests retrieving entries and values in preference order.
+ */
+add_task(function testSortMethods() {
+ let props = new VCardProperties();
+ props.addEntry(new VCardPropertyEntry("email", {}, "text", "third@invalid"));
+ props.addEntry(
+ new VCardPropertyEntry("email", { pref: 2 }, "text", "second@invalid")
+ );
+ props.addEntry(new VCardPropertyEntry("email", {}, "text", "fourth@invalid"));
+ props.addEntry(
+ new VCardPropertyEntry("email", { pref: 1 }, "text", "first@invalid")
+ );
+
+ propertyArrayEqual(props.getAllEntriesSorted("email"), [
+ {
+ name: "email",
+ params: { pref: 1 },
+ type: "text",
+ value: "first@invalid",
+ },
+ {
+ name: "email",
+ params: { pref: 2 },
+ type: "text",
+ value: "second@invalid",
+ },
+ { name: "email", params: {}, type: "text", value: "third@invalid" },
+ { name: "email", params: {}, type: "text", value: "fourth@invalid" },
+ ]);
+
+ Assert.deepEqual(props.getAllValuesSorted("email"), [
+ "first@invalid",
+ "second@invalid",
+ "third@invalid",
+ "fourth@invalid",
+ ]);
+});
+
+/**
+ * Tests the `clone` method of VCardProperties.
+ */
+add_task(function testClone() {
+ let properties = VCardProperties.fromVCard(
+ formatVCard`
+ BEGIN:VCARD
+ FN:this is a test
+ N:test;this;is,a;;
+ EMAIL;PREF=1;TYPE=WORK:test@invalid
+ EMAIL:test@test.invalid
+ END:VCARD`
+ );
+ let clone = properties.clone();
+
+ Assert.deepEqual(clone.entries, properties.entries);
+ Assert.notEqual(clone.entries, properties.entries);
+
+ for (let i = 0; i < 4; i++) {
+ Assert.deepEqual(clone.entries[i].value, properties.entries[i].value);
+ Assert.notEqual(clone.entries[i], properties.entries[i]);
+ Assert.ok(clone.entries[i].equals(properties.entries[i]));
+ }
+
+ Assert.equal(clone.toVCard(), properties.toVCard());
+});
+
+/**
+ * Tests that entries with a group prefix are correctly handled, and the
+ * `getGroupedEntries` method of VCardProperties.
+ */
+add_task(function testGroupEntries() {
+ let vCard = formatVCard`
+ BEGIN:VCARD
+ GROUP1.FN:test
+ GROUP1.X-FOO:bar
+ NOTE:this doesn't have a group
+ END:VCARD`;
+
+ let properties = VCardProperties.fromVCard(vCard);
+
+ let data = [
+ {
+ name: "fn",
+ params: {
+ group: "group1",
+ },
+ type: "text",
+ value: "test",
+ },
+ {
+ name: "x-foo",
+ params: {
+ group: "group1",
+ },
+ type: "unknown",
+ value: "bar",
+ },
+ {
+ name: "note",
+ params: {},
+ type: "text",
+ value: "this doesn't have a group",
+ },
+ ];
+
+ propertyArrayEqual(properties.entries, data);
+ Assert.equal(properties.toVCard(), vCard);
+ propertyArrayEqual(properties.getGroupedEntries("group1"), data.slice(0, 2));
+
+ let clone = properties.clone();
+ propertyArrayEqual(clone.entries, data);
+ Assert.equal(clone.toVCard(), vCard);
+ propertyArrayEqual(clone.getGroupedEntries("group1"), data.slice(0, 2));
+});
+
+/**
+ * Tests that we correctly fix Google's bad escaping of colons in values, and
+ * other characters in URI values.
+ */
+add_task(function testGoogleEscaping() {
+ let vCard = formatVCard`
+ BEGIN:VCARD
+ VERSION:3.0
+ N:test;en\\\\c\\:oding;;;
+ FN:en\\\\c\\:oding test
+ TITLE:title\\:title\\;title\\,title\\\\title\\\\\\:title\\\\\\;title\\\\\\,title\\\\\\\\
+ TEL:tel\\:0123\\\\4567
+ EMAIL:test\\\\test@invalid
+ NOTE:notes\\:\\nnotes\\;\\nnotes\\,\\nnotes\\\\
+ URL:http\\://host/url\\:url\\;url\\,url\\\\url
+ END:VCARD`;
+
+ let goodVCard = formatVCard`
+ BEGIN:VCARD
+ VERSION:3.0
+ N:test;en\\\\c:oding;;;
+ FN:en\\\\c:oding test
+ TITLE:title:title\\;title\\,title\\\\title\\\\:title\\\\\\;title\\\\\\,title\\\\\\\\
+ TEL:tel:01234567
+ EMAIL:test\\\\test@invalid
+ NOTE:notes:\\nnotes\\;\\nnotes\\,\\nnotes\\\\
+ URL:http://host/url:url;url,url\\url
+ END:VCARD`;
+
+ let data = [
+ {
+ name: "version",
+ params: {},
+ type: "text",
+ value: "3.0",
+ },
+ {
+ name: "n",
+ params: {},
+ type: "text",
+ value: ["test", "en\\c:oding", "", "", ""],
+ },
+ {
+ name: "fn",
+ params: {},
+ type: "text",
+ value: "en\\c:oding test",
+ },
+ {
+ name: "title",
+ params: {},
+ type: "text",
+ value: "title:title;title,title\\title\\:title\\;title\\,title\\\\",
+ },
+ {
+ name: "tel",
+ params: {},
+ type: "phone-number",
+ value: "tel:01234567",
+ },
+ {
+ name: "email",
+ params: {},
+ type: "text",
+ value: "test\\test@invalid",
+ },
+ {
+ name: "note",
+ params: {},
+ type: "text",
+ value: "notes:\nnotes;\nnotes,\nnotes\\",
+ },
+ {
+ name: "url",
+ params: {},
+ type: "uri",
+ value: "http://host/url:url;url,url\\url",
+ },
+ ];
+
+ let properties = VCardProperties.fromVCard(vCard, { isGoogleCardDAV: true });
+ propertyArrayEqual(properties.entries, data);
+ Assert.equal(properties.toVCard(), goodVCard);
+
+ let goodProperties = VCardProperties.fromVCard(goodVCard);
+ propertyArrayEqual(goodProperties.entries, data);
+ Assert.equal(goodProperties.toVCard(), goodVCard);
+});