Bug 1579315 - Add a test of importing events; r=pmorris
authorGeoff Lankow <geoff@darktrojan.net>
Thu, 19 Sep 2019 20:40:56 +1200
changeset 79009 315a09d57f1b8ab47495af5a80c19f8fafe11813
parent 79008 944c4a8f2b236ad6afe3423fcc3fc0c711fc669b
child 79010 14db01bcabd2197e6cdb86b3bcde3b7246a7ab22
push id9335
push usermozilla@jorgk.com
push dateThu, 19 Sep 2019 10:56:46 +0000
treeherdertry-comm-central@ec7a23f9bcfd [default view] [failures only]
reviewerspmorris
bugs1579315
Bug 1579315 - Add a test of importing events; r=pmorris
calendar/base/content/import-export.js
calendar/test/browser/browser.ini
calendar/test/browser/browser_import.js
calendar/test/browser/data/import.ics
--- a/calendar/base/content/import-export.js
+++ b/calendar/base/content/import-export.js
@@ -17,115 +17,120 @@ var MODE_TRUNCATE = 0x20;
 
 /**
  * Shows a file dialog, reads the selected file(s) and tries to parse events from it.
  *
  * @param aCalendar  (optional) If specified, the items will be imported directly
  *                              into the calendar
  */
 function loadEventsFromFile(aCalendar) {
-  let picker = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
-  picker.init(window, cal.l10n.getCalString("filepickerTitleImport"), Ci.nsIFilePicker.modeOpen);
-  picker.defaultExtension = "ics";
+  return new Promise(resolve => {
+    let picker = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
+    picker.init(window, cal.l10n.getCalString("filepickerTitleImport"), Ci.nsIFilePicker.modeOpen);
+    picker.defaultExtension = "ics";
 
-  // Get a list of importers
-  let contractids = [];
-  let currentListLength = 0;
-  let defaultCIDIndex = 0;
-  for (let { data } of Services.catMan.enumerateCategory("cal-importers")) {
-    let contractid = Services.catMan.getCategoryEntry("cal-importers", data);
-    let importer;
-    try {
-      importer = Cc[contractid].getService(Ci.calIImporter);
-    } catch (e) {
-      cal.WARN("Could not initialize importer: " + contractid + "\nError: " + e);
-      continue;
-    }
-    let types = importer.getFileTypes({});
-    for (let type of types) {
-      picker.appendFilter(type.description, type.extensionFilter);
-      if (type.extensionFilter == "*." + picker.defaultExtension) {
-        picker.filterIndex = currentListLength;
-        defaultCIDIndex = currentListLength;
+    // Get a list of importers
+    let contractids = [];
+    let currentListLength = 0;
+    let defaultCIDIndex = 0;
+    for (let { data } of Services.catMan.enumerateCategory("cal-importers")) {
+      let contractid = Services.catMan.getCategoryEntry("cal-importers", data);
+      let importer;
+      try {
+        importer = Cc[contractid].getService(Ci.calIImporter);
+      } catch (e) {
+        cal.WARN("Could not initialize importer: " + contractid + "\nError: " + e);
+        continue;
       }
-      contractids.push(contractid);
-      currentListLength++;
-    }
-  }
-
-  picker.open(rv => {
-    if (rv != Ci.nsIFilePicker.returnOK || !picker.file || !picker.file.path) {
-      return;
-    }
-
-    let filterIndex = picker.filterIndex;
-    if (picker.filterIndex < 0 || picker.filterIndex > contractids.length) {
-      // For some reason the wrong filter was selected, assume default extension
-      filterIndex = defaultCIDIndex;
+      let types = importer.getFileTypes({});
+      for (let type of types) {
+        picker.appendFilter(type.description, type.extensionFilter);
+        if (type.extensionFilter == "*." + picker.defaultExtension) {
+          picker.filterIndex = currentListLength;
+          defaultCIDIndex = currentListLength;
+        }
+        contractids.push(contractid);
+        currentListLength++;
+      }
     }
 
-    let filePath = picker.file.path;
-    let importer = Cc[contractids[filterIndex]].getService(Ci.calIImporter);
+    picker.open(async returnValue => {
+      if (returnValue != Ci.nsIFilePicker.returnOK || !picker.file || !picker.file.path) {
+        return;
+      }
 
-    let inputStream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
-      Ci.nsIFileInputStream
-    );
-    let items = [];
-    let exception;
+      let filterIndex = picker.filterIndex;
+      if (picker.filterIndex < 0 || picker.filterIndex > contractids.length) {
+        // For some reason the wrong filter was selected, assume default extension
+        filterIndex = defaultCIDIndex;
+      }
+
+      let filePath = picker.file.path;
+      let importer = Cc[contractids[filterIndex]].getService(Ci.calIImporter);
 
-    try {
-      inputStream.init(picker.file, MODE_RDONLY, parseInt("0444", 8), {});
-      items = importer.importFromStream(inputStream, {});
-    } catch (ex) {
-      exception = ex;
-      switch (ex.result) {
-        case Ci.calIErrors.INVALID_TIMEZONE:
-          cal.showError(cal.l10n.getCalString("timezoneError", [filePath]), window);
-          break;
-        default:
-          cal.showError(cal.l10n.getCalString("unableToRead") + filePath + "\n" + ex, window);
+      let inputStream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
+        Ci.nsIFileInputStream
+      );
+      let items = [];
+      let exception;
+
+      try {
+        inputStream.init(picker.file, MODE_RDONLY, parseInt("0444", 8), {});
+        items = importer.importFromStream(inputStream, {});
+      } catch (ex) {
+        exception = ex;
+        switch (ex.result) {
+          case Ci.calIErrors.INVALID_TIMEZONE:
+            cal.showError(cal.l10n.getCalString("timezoneError", [filePath]), window);
+            break;
+          default:
+            cal.showError(cal.l10n.getCalString("unableToRead") + filePath + "\n" + ex, window);
+        }
+      } finally {
+        inputStream.close();
       }
-    } finally {
-      inputStream.close();
-    }
 
-    if (!items.length && !exception) {
-      // the ics did not contain any events, so there's no need to proceed. But we should
-      // notify the user about it, if we haven't before.
-      cal.showError(cal.l10n.getCalString("noItemsInCalendarFile", [filePath]), window);
-      return;
-    }
+      if (!items.length && !exception) {
+        // the ics did not contain any events, so there's no need to proceed. But we should
+        // notify the user about it, if we haven't before.
+        cal.showError(cal.l10n.getCalString("noItemsInCalendarFile", [filePath]), window);
+        return;
+      }
 
-    if (aCalendar) {
-      putItemsIntoCal(aCalendar, items);
-      return;
-    }
+      if (aCalendar) {
+        await putItemsIntoCal(aCalendar, items);
+        resolve();
+        return;
+      }
 
-    let calendars = cal.getCalendarManager().getCalendars({});
-    calendars = calendars.filter(cal.acl.isCalendarWritable);
+      let calendars = cal.getCalendarManager().getCalendars({});
+      calendars = calendars.filter(cal.acl.isCalendarWritable);
 
-    if (calendars.length == 1) {
-      // There's only one calendar, so it's silly to ask what calendar
-      // the user wants to import into.
-      putItemsIntoCal(calendars[0], items, filePath);
-    } else if (calendars.length > 1) {
-      // Ask what calendar to import into
-      let args = {};
-      args.onOk = aCal => {
-        putItemsIntoCal(aCal, items, filePath);
-      };
-      args.calendars = calendars;
-      args.promptText = cal.l10n.getCalString("importPrompt");
-      openDialog(
-        "chrome://calendar/content/chooseCalendarDialog.xul",
-        "_blank",
-        "chrome,titlebar,modal,resizable",
-        args
-      );
-    }
+      if (calendars.length == 1) {
+        // There's only one calendar, so it's silly to ask what calendar
+        // the user wants to import into.
+        await putItemsIntoCal(calendars[0], items, filePath);
+        resolve();
+      } else if (calendars.length > 1) {
+        // Ask what calendar to import into
+        let args = {};
+        args.onOk = async aCal => {
+          await putItemsIntoCal(aCal, items, filePath);
+          resolve();
+        };
+        args.calendars = calendars;
+        args.promptText = cal.l10n.getCalString("importPrompt");
+        openDialog(
+          "chrome://calendar/content/chooseCalendarDialog.xul",
+          "_blank",
+          "chrome,titlebar,modal,resizable",
+          args
+        );
+      }
+    });
   });
 }
 
 /**
  * Put items into a certain calendar, catching errors and showing them to the
  * user.
  *
  * @param destCal       The destination calendar.
--- a/calendar/test/browser/browser.ini
+++ b/calendar/test/browser/browser.ini
@@ -5,11 +5,13 @@ prefs =
   ldap_2.servers.osx.dirType=-1
   ldap_2.servers.osx.uri=
   mail.provider.suppress_dialog_on_startup=true
   mail.spotlight.firstRunDone=true
   mail.winsearch.firstRunDone=true
   mailnews.start_page.override_url=about:blank
   mailnews.start_page.url=about:blank
 subsuite = thunderbird
+support-files = data/**
 
 [browser_calendarList.js]
+[browser_import.js]
 [browser_tabs.js]
new file mode 100644
--- /dev/null
+++ b/calendar/test/browser/browser_import.js
@@ -0,0 +1,38 @@
+/* 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/. */
+
+// This tests importing an ICS file. Rather than using the UI to trigger the
+// import, loadEventsFromFile is called directly, so that we can be sure it
+// has finished by waiting on the returned Promise.
+
+const { MockFilePicker } = ChromeUtils.import("resource://specialpowers/MockFilePicker.jsm");
+const ChromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry);
+
+add_task(async () => {
+  let chromeUrl = Services.io.newURI(getRootDirectory(gTestPath) + "data/import.ics");
+  let fileUrl = ChromeRegistry.convertChromeURL(chromeUrl);
+  let file = fileUrl.QueryInterface(Ci.nsIFileURL).file;
+
+  MockFilePicker.init(content);
+  MockFilePicker.setFiles([file]);
+  MockFilePicker.returnValue = MockFilePicker.returnOK;
+
+  await loadEventsFromFile();
+
+  let calendar = cal.getCalendarManager().getCalendars({})[0];
+  let promiseCalendar = cal.async.promisifyCalendar(calendar);
+  let result = await promiseCalendar.getItems(
+    Ci.calICalendar.ITEM_FILTER_ALL_ITEMS,
+    0,
+    cal.createDateTime("20190101T000000"),
+    cal.createDateTime("20190102T000000")
+  );
+  is(result.length, 4);
+
+  for (let item of result) {
+    await promiseCalendar.deleteItem(item);
+  }
+
+  MockFilePicker.cleanup();
+});
new file mode 100644
--- /dev/null
+++ b/calendar/test/browser/data/import.ics
@@ -0,0 +1,24 @@
+BEGIN:VCALENDAR
+PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:Event One
+DTSTART:20190101T150000
+DTEND:20190101T160000
+END:VEVENT
+BEGIN:VEVENT
+SUMMARY:Event Two
+DTSTART:20190101T160000
+DTEND:20190101T170000
+END:VEVENT
+BEGIN:VEVENT
+SUMMARY:Event Three
+DTSTART:20190101T170000
+DTEND:20190101T180000
+END:VEVENT
+BEGIN:VEVENT
+SUMMARY:Event Four
+DTSTART:20190101T180000
+DTEND:20190101T190000
+END:VEVENT
+END:VCALENDAR