summaryrefslogtreecommitdiffstats
path: root/comm/calendar/test/unit/test_alarm.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--comm/calendar/test/unit/test_alarm.js674
1 files changed, 674 insertions, 0 deletions
diff --git a/comm/calendar/test/unit/test_alarm.js b/comm/calendar/test/unit/test_alarm.js
new file mode 100644
index 0000000000..14b2ce76bd
--- /dev/null
+++ b/comm/calendar/test/unit/test_alarm.js
@@ -0,0 +1,674 @@
+/* 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/. */
+
+var { XPCOMUtils } = ChromeUtils.importESModule("resource://gre/modules/XPCOMUtils.sys.mjs");
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+ CalAlarm: "resource:///modules/CalAlarm.jsm",
+ CalAttachment: "resource:///modules/CalAttachment.jsm",
+ CalAttendee: "resource:///modules/CalAttendee.jsm",
+ CalTodo: "resource:///modules/CalTodo.jsm",
+});
+
+function run_tests() {
+ test_initial_creation();
+
+ test_display_alarm();
+ test_email_alarm();
+ test_audio_alarm();
+ test_custom_alarm();
+ test_repeat();
+ test_xprop();
+
+ test_dates();
+
+ test_clone();
+ test_immutable();
+ test_serialize();
+ test_strings();
+}
+
+function run_test() {
+ do_calendar_startup(run_tests);
+}
+
+function test_initial_creation() {
+ dump("Testing initial creation...");
+ let alarm = new CalAlarm();
+
+ let passed;
+ try {
+ // eslint-disable-next-line no-unused-expressions
+ alarm.icalString;
+ passed = false;
+ } catch (e) {
+ passed = true;
+ }
+ if (!passed) {
+ do_throw("Fresh calIAlarm should not produce a valid icalString");
+ }
+ dump("Done\n");
+}
+
+function test_display_alarm() {
+ dump("Testing DISPLAY alarms...");
+ let alarm = new CalAlarm();
+ // Set ACTION to DISPLAY, make sure this was not rejected
+ alarm.action = "DISPLAY";
+ equal(alarm.action, "DISPLAY");
+
+ // Set a Description, REQUIRED for ACTION:DISPLAY
+ alarm.description = "test";
+ equal(alarm.description, "test");
+
+ // SUMMARY is not valid for ACTION:DISPLAY
+ alarm.summary = "test";
+ equal(alarm.summary, null);
+
+ // No attendees allowed
+ let attendee = new CalAttendee();
+ attendee.id = "mailto:horst";
+
+ throws(() => {
+ // DISPLAY alarm should not be able to save attendees
+ alarm.addAttendee(attendee);
+ }, /Alarm type AUDIO\/DISPLAY may not have attendees/);
+
+ throws(() => {
+ // DISPLAY alarm should not be able to save attachment
+ alarm.addAttachment(new CalAttachment());
+ }, /Alarm type DISPLAY may not have attachments/);
+
+ dump("Done\n");
+}
+
+function test_email_alarm() {
+ dump("Testing EMAIL alarms...");
+ let alarm = new CalAlarm();
+ // Set ACTION to DISPLAY, make sure this was not rejected
+ alarm.action = "EMAIL";
+ equal(alarm.action, "EMAIL");
+
+ // Set a Description, REQUIRED for ACTION:EMAIL
+ alarm.description = "description";
+ equal(alarm.description, "description");
+
+ // Set a Summary, REQUIRED for ACTION:EMAIL
+ alarm.summary = "summary";
+ equal(alarm.summary, "summary");
+
+ // Set an offset of some sort
+ alarm.related = Ci.calIAlarm.ALARM_RELATED_START;
+ alarm.offset = cal.createDuration();
+
+ // Check for at least one attendee
+ let attendee1 = new CalAttendee();
+ attendee1.id = "mailto:horst";
+ let attendee2 = new CalAttendee();
+ attendee2.id = "mailto:gustav";
+
+ equal(alarm.getAttendees().length, 0);
+ alarm.addAttendee(attendee1);
+ equal(alarm.getAttendees().length, 1);
+ alarm.addAttendee(attendee2);
+ equal(alarm.getAttendees().length, 2);
+ alarm.addAttendee(attendee1);
+ let addedAttendees = alarm.getAttendees();
+ equal(addedAttendees.length, 2);
+ equal(addedAttendees[0].wrappedJSObject, attendee2);
+ equal(addedAttendees[1].wrappedJSObject, attendee1);
+
+ ok(!!alarm.icalComponent.serializeToICS().match(/mailto:horst/));
+ ok(!!alarm.icalComponent.serializeToICS().match(/mailto:gustav/));
+
+ alarm.deleteAttendee(attendee1);
+ equal(alarm.getAttendees().length, 1);
+
+ alarm.clearAttendees();
+ equal(alarm.getAttendees().length, 0);
+
+ // Make sure attendees are correctly folded/imported
+ alarm.icalString = dedent`
+ BEGIN:VALARM
+ ACTION:EMAIL
+ TRIGGER;VALUE=DURATION:-PT5M
+ ATTENDEE:mailto:test@example.com
+ ATTENDEE:mailto:test@example.com
+ ATTENDEE:mailto:test2@example.com
+ END:VALARM
+ `;
+ equal(alarm.icalString.match(/ATTENDEE:mailto:test@example.com/g).length, 1);
+ equal(alarm.icalString.match(/ATTENDEE:mailto:test2@example.com/g).length, 1);
+
+ // TODO test attachments
+ dump("Done\n");
+}
+
+function test_audio_alarm() {
+ dump("Testing AUDIO alarms...");
+ let alarm = new CalAlarm();
+ alarm.related = Ci.calIAlarm.ALARM_RELATED_ABSOLUTE;
+ alarm.alarmDate = cal.createDateTime();
+ // Set ACTION to AUDIO, make sure this was not rejected
+ alarm.action = "AUDIO";
+ equal(alarm.action, "AUDIO");
+
+ // No Description for ACTION:AUDIO
+ alarm.description = "description";
+ equal(alarm.description, null);
+
+ // No Summary, for ACTION:AUDIO
+ alarm.summary = "summary";
+ equal(alarm.summary, null);
+
+ // No attendees allowed
+ let attendee = new CalAttendee();
+ attendee.id = "mailto:horst";
+
+ try {
+ alarm.addAttendee(attendee);
+ do_throw("AUDIO alarm should not be able to save attendees");
+ } catch (e) {
+ // TODO looks like this test is disabled. Why?
+ }
+
+ // Test attachments
+ let sound = new CalAttachment();
+ sound.uri = Services.io.newURI("file:///sound.wav");
+ let sound2 = new CalAttachment();
+ sound2.uri = Services.io.newURI("file:///sound2.wav");
+
+ // Adding an attachment should work
+ alarm.addAttachment(sound);
+ let addedAttachments = alarm.getAttachments();
+ equal(addedAttachments.length, 1);
+ equal(addedAttachments[0].wrappedJSObject, sound);
+ ok(alarm.icalString.includes("ATTACH:file:///sound.wav"));
+
+ // Adding twice shouldn't change anything
+ alarm.addAttachment(sound);
+ addedAttachments = alarm.getAttachments();
+ equal(addedAttachments.length, 1);
+ equal(addedAttachments[0].wrappedJSObject, sound);
+
+ try {
+ alarm.addAttachment(sound2);
+ do_throw("Adding a second attachment should fail for type AUDIO");
+ } catch (e) {
+ // TODO looks like this test is disabled. Why?
+ }
+
+ // Deleting should work
+ alarm.deleteAttachment(sound);
+ addedAttachments = alarm.getAttachments();
+ equal(addedAttachments.length, 0);
+
+ // As well as clearing
+ alarm.addAttachment(sound);
+ alarm.clearAttachments();
+ addedAttachments = alarm.getAttachments();
+ equal(addedAttachments.length, 0);
+
+ // AUDIO alarms should only be allowing one attachment, and folding any with the same value
+ alarm.icalString = dedent`
+ BEGIN:VALARM
+ ACTION:AUDIO
+ TRIGGER;VALUE=DURATION:-PT5M
+ ATTACH:Basso
+ UID:28F8007B-FE56-442E-917C-1F4E48DD406A
+ X-APPLE-DEFAULT-ALARM:TRUE
+ ATTACH:Basso
+ END:VALARM
+ `;
+ equal(alarm.icalString.match(/ATTACH:Basso/g).length, 1);
+
+ dump("Done\n");
+}
+
+function test_custom_alarm() {
+ dump("Testing X-SMS (custom) alarms...");
+ let alarm = new CalAlarm();
+ // Set ACTION to a custom value, make sure this was not rejected
+ alarm.action = "X-SMS";
+ equal(alarm.action, "X-SMS");
+
+ // There is no restriction on DESCRIPTION for custom alarms
+ alarm.description = "description";
+ equal(alarm.description, "description");
+
+ // There is no restriction on SUMMARY for custom alarms
+ alarm.summary = "summary";
+ equal(alarm.summary, "summary");
+
+ // Test for attendees
+ let attendee1 = new CalAttendee();
+ attendee1.id = "mailto:horst";
+ let attendee2 = new CalAttendee();
+ attendee2.id = "mailto:gustav";
+
+ equal(alarm.getAttendees().length, 0);
+ alarm.addAttendee(attendee1);
+ equal(alarm.getAttendees().length, 1);
+ alarm.addAttendee(attendee2);
+ equal(alarm.getAttendees().length, 2);
+ alarm.addAttendee(attendee1);
+ equal(alarm.getAttendees().length, 2);
+
+ alarm.deleteAttendee(attendee1);
+ equal(alarm.getAttendees().length, 1);
+
+ alarm.clearAttendees();
+ equal(alarm.getAttendees().length, 0);
+
+ // Test for attachments
+ let attach1 = new CalAttachment();
+ attach1.uri = Services.io.newURI("file:///example.txt");
+ let attach2 = new CalAttachment();
+ attach2.uri = Services.io.newURI("file:///example2.txt");
+
+ alarm.addAttachment(attach1);
+ alarm.addAttachment(attach2);
+
+ let addedAttachments = alarm.getAttachments();
+ equal(addedAttachments.length, 2);
+ equal(addedAttachments[0].wrappedJSObject, attach1);
+ equal(addedAttachments[1].wrappedJSObject, attach2);
+
+ alarm.deleteAttachment(attach1);
+ addedAttachments = alarm.getAttachments();
+ equal(addedAttachments.length, 1);
+
+ alarm.clearAttachments();
+ addedAttachments = alarm.getAttachments();
+ equal(addedAttachments.length, 0);
+}
+
+// Check if any combination of REPEAT and DURATION work as expected.
+function test_repeat() {
+ dump("Testing REPEAT and DURATION properties...");
+ let alarm = new CalAlarm();
+
+ // Check initial value
+ equal(alarm.repeat, 0);
+ equal(alarm.repeatOffset, null);
+ equal(alarm.repeatDate, null);
+
+ // Should not be able to get REPEAT when DURATION is not set
+ alarm.repeat = 1;
+ equal(alarm.repeat, 0);
+
+ // Both REPEAT and DURATION should be accessible, when the two are set.
+ alarm.repeatOffset = cal.createDuration();
+ notEqual(alarm.repeatOffset, null);
+ notEqual(alarm.repeat, 0);
+
+ // Should not be able to get DURATION when REPEAT is not set
+ alarm.repeat = null;
+ equal(alarm.repeatOffset, null);
+
+ // Should be able to unset alarm DURATION attribute. (REPEAT already tested above)
+ try {
+ alarm.repeatOffset = null;
+ } catch (e) {
+ do_throw("Could not set repeatOffset attribute to null" + e);
+ }
+
+ // Check unset value
+ equal(alarm.repeat, 0);
+ equal(alarm.repeatOffset, null);
+
+ // Check repeatDate
+ alarm = new CalAlarm();
+ alarm.related = Ci.calIAlarm.ALARM_RELATED_ABSOLUTE;
+ alarm.alarmDate = cal.createDateTime();
+ alarm.repeat = 1;
+ alarm.repeatOffset = cal.createDuration();
+ alarm.repeatOffset.inSeconds = 3600;
+
+ let date = alarm.alarmDate.clone();
+ date.second += 3600;
+ equal(alarm.repeatDate.icalString, date.icalString);
+
+ dump("Done\n");
+}
+
+function test_xprop() {
+ dump("Testing X-Props...");
+ let alarm = new CalAlarm();
+ alarm.setProperty("X-PROP", "X-VALUE");
+ ok(alarm.hasProperty("X-PROP"));
+ equal(alarm.getProperty("X-PROP"), "X-VALUE");
+ alarm.deleteProperty("X-PROP");
+ ok(!alarm.hasProperty("X-PROP"));
+ equal(alarm.getProperty("X-PROP"), null);
+
+ // also check X-MOZ-LASTACK prop
+ let date = cal.createDateTime();
+ alarm.setProperty("X-MOZ-LASTACK", date.icalString);
+ alarm.action = "DISPLAY";
+ alarm.description = "test";
+ alarm.related = Ci.calIAlarm.ALARM_RELATED_START;
+ alarm.offset = cal.createDuration("-PT5M");
+ ok(alarm.icalComponent.serializeToICS().includes(date.icalString));
+
+ alarm.deleteProperty("X-MOZ-LASTACK");
+ ok(!alarm.icalComponent.serializeToICS().includes(date.icalString));
+ dump("Done\n");
+}
+
+function test_dates() {
+ dump("Testing alarm dates...");
+ let passed;
+ // Initial value
+ let alarm = new CalAlarm();
+ equal(alarm.alarmDate, null);
+ equal(alarm.offset, null);
+
+ // Set an offset and check it
+ alarm.related = Ci.calIAlarm.ALARM_RELATED_START;
+ let offset = cal.createDuration("-PT5M");
+ alarm.offset = offset;
+ equal(alarm.alarmDate, null);
+ equal(alarm.offset, offset);
+ try {
+ alarm.alarmDate = cal.createDateTime();
+ passed = false;
+ } catch (e) {
+ passed = true;
+ }
+ if (!passed) {
+ do_throw("Setting alarmDate when alarm is relative should not succeed");
+ }
+
+ // Set an absolute time and check it
+ alarm.related = Ci.calIAlarm.ALARM_RELATED_ABSOLUTE;
+ let alarmDate = createDate(2007, 0, 1, true, 2, 0, 0);
+ alarm.alarmDate = alarmDate;
+ equal(alarm.alarmDate.icalString, alarmDate.icalString);
+ equal(alarm.offset, null);
+ try {
+ alarm.offset = cal.createDuration();
+ passed = false;
+ } catch (e) {
+ passed = true;
+ }
+ if (!passed) {
+ do_throw("Setting offset when alarm is absolute should not succeed");
+ }
+
+ dump("Done\n");
+}
+
+var propMap = {
+ related: Ci.calIAlarm.ALARM_RELATED_START,
+ repeat: 1,
+ action: "X-TEST",
+ description: "description",
+ summary: "summary",
+ offset: cal.createDuration("PT4M"),
+ repeatOffset: cal.createDuration("PT1M"),
+};
+var clonePropMap = {
+ related: Ci.calIAlarm.ALARM_RELATED_END,
+ repeat: 2,
+ action: "X-CHANGED",
+ description: "description-changed",
+ summary: "summary-changed",
+ offset: cal.createDuration("PT5M"),
+ repeatOffset: cal.createDuration("PT2M"),
+};
+
+function test_immutable() {
+ dump("Testing immutable alarms...");
+ let alarm = new CalAlarm();
+ // Set up each attribute
+ for (let prop in propMap) {
+ alarm[prop] = propMap[prop];
+ }
+
+ // Set up some extra props
+ alarm.setProperty("X-FOO", "X-VAL");
+ alarm.setProperty("X-DATEPROP", cal.createDateTime());
+ alarm.addAttendee(new CalAttendee());
+
+ // Initial checks
+ ok(alarm.isMutable);
+ alarm.makeImmutable();
+ ok(!alarm.isMutable);
+ alarm.makeImmutable();
+ ok(!alarm.isMutable);
+
+ // Check each attribute
+ for (let prop in propMap) {
+ try {
+ alarm[prop] = propMap[prop];
+ } catch (e) {
+ equal(e.result, Cr.NS_ERROR_OBJECT_IS_IMMUTABLE);
+ continue;
+ }
+ do_throw("Attribute " + prop + " was writable while item was immutable");
+ }
+
+ // Functions
+ throws(() => {
+ alarm.setProperty("X-FOO", "changed");
+ }, /Can not modify immutable data container/);
+
+ throws(() => {
+ alarm.deleteProperty("X-FOO");
+ }, /Can not modify immutable data container/);
+
+ ok(!alarm.getProperty("X-DATEPROP").isMutable);
+
+ dump("Done\n");
+}
+
+function test_clone() {
+ dump("Testing cloning alarms...");
+ let alarm = new CalAlarm();
+ // Set up each attribute
+ for (let prop in propMap) {
+ alarm[prop] = propMap[prop];
+ }
+
+ // Set up some extra props
+ alarm.setProperty("X-FOO", "X-VAL");
+ alarm.setProperty("X-DATEPROP", cal.createDateTime());
+ alarm.addAttendee(new CalAttendee());
+
+ // Make a copy
+ let newAlarm = alarm.clone();
+ newAlarm.makeImmutable();
+ newAlarm = newAlarm.clone();
+ ok(newAlarm.isMutable);
+
+ // Check if item is still the same
+ // TODO This is not quite optimal, maybe someone can find a better way to do
+ // the comparisons.
+ for (let prop in propMap) {
+ if (prop == "item") {
+ equal(alarm.item.icalString, newAlarm.item.icalString);
+ } else {
+ try {
+ alarm[prop].QueryInterface(Ci.nsISupports);
+ equal(alarm[prop].icalString, newAlarm[prop].icalString);
+ } catch {
+ equal(alarm[prop], newAlarm[prop]);
+ }
+ }
+ }
+
+ // Check if changes on the cloned object do not affect the original object.
+ for (let prop in clonePropMap) {
+ newAlarm[prop] = clonePropMap[prop];
+ dump("Checking " + prop + "...");
+ notEqual(alarm[prop], newAlarm[prop]);
+ dump("OK!\n");
+ break;
+ }
+
+ // Check x props
+ alarm.setProperty("X-FOO", "BAR");
+ equal(alarm.getProperty("X-FOO"), "BAR");
+ let date = alarm.getProperty("X-DATEPROP");
+ equal(date.isMutable, true);
+
+ // Test xprop params
+ alarm.icalString =
+ "BEGIN:VALARM\n" +
+ "ACTION:DISPLAY\n" +
+ "TRIGGER:-PT15M\n" +
+ "X-FOO;X-PARAM=PARAMVAL:BAR\n" +
+ "DESCRIPTION:TEST\n" +
+ "END:VALARM";
+
+ newAlarm = alarm.clone();
+ equal(alarm.icalString, newAlarm.icalString);
+
+ dump("Done\n");
+}
+
+function test_serialize() {
+ // most checks done by other tests, these don't fit into categories
+ let alarm = new CalAlarm();
+
+ throws(
+ () => {
+ alarm.icalComponent = cal.icsService.createIcalComponent("BARF");
+ },
+ /0x80070057/,
+ "Invalid Argument"
+ );
+
+ function addProp(name, value) {
+ let prop = cal.icsService.createIcalProperty(name);
+ prop.value = value;
+ comp.addProperty(prop);
+ }
+ function addActionDisplay() {
+ addProp("ACTION", "DISPLAY");
+ }
+ function addActionEmail() {
+ addProp("ACTION", "EMAIL");
+ }
+ function addTrigger() {
+ addProp("TRIGGER", "-PT15M");
+ }
+ function addDescr() {
+ addProp("DESCRIPTION", "TEST");
+ }
+ function addDuration() {
+ addProp("DURATION", "-PT15M");
+ }
+ function addRepeat() {
+ addProp("REPEAT", "1");
+ }
+ function addAttendee() {
+ addProp("ATTENDEE", "mailto:horst");
+ }
+ function addAttachment() {
+ addProp("ATTACH", "data:yeah");
+ }
+
+ // All is there, should not throw
+ let comp = cal.icsService.createIcalComponent("VALARM");
+ addActionDisplay();
+ addTrigger();
+ addDescr();
+ addDuration();
+ addRepeat();
+ alarm.icalComponent = comp;
+ alarm.toString();
+
+ // Attachments and attendees
+ comp = cal.icsService.createIcalComponent("VALARM");
+ addActionEmail();
+ addTrigger();
+ addDescr();
+ addAttendee();
+ addAttachment();
+ alarm.icalComponent = comp;
+ alarm.toString();
+
+ // Missing action
+ throws(
+ () => {
+ comp = cal.icsService.createIcalComponent("VALARM");
+ addTrigger();
+ addDescr();
+ alarm.icalComponent = comp;
+ },
+ /Illegal value/,
+ "Invalid Argument"
+ );
+
+ // Missing trigger
+ throws(
+ () => {
+ comp = cal.icsService.createIcalComponent("VALARM");
+ addActionDisplay();
+ addDescr();
+ alarm.icalComponent = comp;
+ },
+ /Illegal value/,
+ "Invalid Argument"
+ );
+
+ // Missing duration with repeat
+ throws(
+ () => {
+ comp = cal.icsService.createIcalComponent("VALARM");
+ addActionDisplay();
+ addTrigger();
+ addDescr();
+ addRepeat();
+ alarm.icalComponent = comp;
+ },
+ /Illegal value/,
+ "Invalid Argument"
+ );
+
+ // Missing repeat with duration
+ throws(
+ () => {
+ comp = cal.icsService.createIcalComponent("VALARM");
+ addActionDisplay();
+ addTrigger();
+ addDescr();
+ addDuration();
+ alarm.icalComponent = comp;
+ },
+ /Illegal value/,
+ "Invalid Argument"
+ );
+}
+
+function test_strings() {
+ // Serializing the string shouldn't throw, but we don't really care about
+ // the string itself.
+ let alarm = new CalAlarm();
+ alarm.action = "DISPLAY";
+ alarm.related = Ci.calIAlarm.ALARM_RELATED_ABSOLUTE;
+ alarm.alarmDate = cal.createDateTime();
+ alarm.toString();
+
+ alarm.related = Ci.calIAlarm.ALARM_RELATED_START;
+ alarm.offset = cal.createDuration();
+ alarm.toString();
+ alarm.toString(new CalTodo());
+
+ alarm.related = Ci.calIAlarm.ALARM_RELATED_END;
+ alarm.offset = cal.createDuration();
+ alarm.toString();
+ alarm.toString(new CalTodo());
+
+ alarm.offset = cal.createDuration("P1D");
+ alarm.toString();
+
+ alarm.offset = cal.createDuration("PT1H");
+ alarm.toString();
+
+ alarm.offset = cal.createDuration("-PT1H");
+ alarm.toString();
+}