Bug 549336 - Custom filters generate an error in searchSpec, r=asuth
authorKent James <kent@caspia.com>
Tue, 30 Mar 2010 11:20:14 -0700
changeset 5328 dff247dd5353e11b1311c1f6a814b20ce9572c1e
parent 5327 76ed45533954d00e1e8d37c78c959a353e0c3880
child 5329 f95c58ffa76a7195c41ab7178eb569b7843df650
push idunknown
push userunknown
push dateunknown
reviewersasuth
bugs549336
Bug 549336 - Custom filters generate an error in searchSpec, r=asuth
mail/base/modules/searchSpec.js
mail/base/test/unit/resources/viewWrapperTestUtils.js
mail/base/test/unit/test_viewWrapper_virtualFolderCustomTerm.js
mailnews/test/resources/messageInjection.js
--- a/mail/base/modules/searchSpec.js
+++ b/mail/base/modules/searchSpec.js
@@ -409,20 +409,34 @@ SearchSpec.prototype = {
           offlineScope = nsMsgSearchScope.onlineManual;
 
         let offlineValidityTable = validityManager.getTable(offlineScope);
         let offlineAvailable = true;
         let onlineAvailable = true;
         for each (let term in fixIterator(session.searchTerms,
                                           nsIMsgSearchTerm)) {
           if (!term.matchAll) {
-            if (!offlineValidityTable.getAvailable(term.attrib, term.op))
-              offlineAvailable = false;
-            if (!onlineValidityTable.getAvailable(term.attrib, term.op))
-              onlineAvailable = false;
+            // for custom terms, we need to getAvailable from the custom term
+            if (term.attrib == Ci.nsMsgSearchAttrib.Custom) {
+              let filterService = Cc["@mozilla.org/messenger/services/filters;1"]
+                                    .getService(Ci.nsIMsgFilterService);
+              let customTerm = filterService.getCustomTerm(term.customId);
+              if (customTerm) {
+                offlineAvailable = customTerm.getAvailable(offlineScope, term.op);
+                onlineAvailable = customTerm.getAvailable(serverScope, term.op);
+              }
+              else // maybe an extension with a custom term was unloaded?
+                Cu.reportError("Custom search term " + term.customId + " missing");
+            }
+            else {
+              if (!offlineValidityTable.getAvailable(term.attrib, term.op))
+                offlineAvailable = false;
+              if (!onlineValidityTable.getAvailable(term.attrib, term.op))
+                onlineAvailable = false;
+            }
           }
         }
         // If both scopes work, honor the onlineSearch request, unless we're
         // filtering (quick search and/or a view selected)
         if (onlineAvailable && offlineAvailable)
           scope = (!filtering && this.onlineSearch) ? serverScope : offlineScope;
         // If only one works, use it. Otherwise, default to offline
         else if (onlineAvailable)
--- a/mail/base/test/unit/resources/viewWrapperTestUtils.js
+++ b/mail/base/test/unit/resources/viewWrapperTestUtils.js
@@ -39,23 +39,26 @@ Components.utils.import("resource://app/
 Components.utils.import("resource://app/modules/mailViewManager.js");
 Components.utils.import("resource://app/modules/quickSearchManager.js");
 Components.utils.import("resource://app/modules/virtualFolderWrapper.js");
 
 /**
  * Do initialization for xpcshell-tests; not used by
  *  test-folder-display-helpers.js, our friendly mozmill test helper.
  */
-function initViewWrapperTestUtils() {
+function initViewWrapperTestUtils(aInjectionConfig) {
   gMessageGenerator = new MessageGenerator();
   gMessageScenarioFactory = new MessageScenarioFactory(gMessageGenerator);
 
   async_test_runner_register_helper(VWTU_testHelper);
   register_message_injection_listener(VWTU_testHelper);
-  configure_message_injection({mode: "local"});
+  if (aInjectionConfig)
+    configure_message_injection(aInjectionConfig);
+  else
+    configure_message_injection({mode: "local"});
 }
 
 // something less sucky than do_check_true
 function assert_true(aBeTrue, aWhy, aDumpView) {
   if (!aBeTrue) {
     if (aDumpView)
       dump_view_state(VWTU_testHelper.active_view_wrappers[0]);
     do_throw(aWhy);
new file mode 100644
--- /dev/null
+++ b/mail/base/test/unit/test_viewWrapper_virtualFolderCustomTerm.js
@@ -0,0 +1,73 @@
+/**
+ * Test DBViewWrapper against a virtual folder with a custom search term.
+ *
+ *  This test uses an imap message to specifically test the issues from
+ *   bug 549336. The code is derived from test_viewWrapper_virtualFolder.js
+ *
+ *  Original author: Kent James
+ */
+
+load("../../mailnews/resources/logHelper.js");
+load("../../mailnews/resources/asyncTestUtils.js");
+
+load("../../mailnews/resources/messageGenerator.js");
+load("../../mailnews/resources/messageModifier.js");
+load("../../mailnews/resources/messageInjection.js");
+
+load("resources/viewWrapperTestUtils.js");
+
+initViewWrapperTestUtils({mode: "imap", offline: false});
+
+/**
+ * A custom search term, that just does Subject Contains
+ */
+gCustomSearchTermSubject = {
+  id: "mailnews@mozilla.org#test",
+  name: "Test-mailbase Subject",
+  getEnabled: function subject_getEnabled(scope, op) {
+    return true;
+  },
+  getAvailable: function subject_getAvailable(scope, op) {
+    return true;
+  },
+  getAvailableOperators: function subject_getAvailableOperators(scope, length) {
+    length.value = 1;
+    return [Components.interfaces.nsMsgSearchOp.Contains];
+  },
+  match: function subject_match(aMsgHdr, aSearchValue, aSearchOp) {
+    return (aMsgHdr.subject.indexOf(aSearchValue) != -1);
+  },
+  needsBody: false,
+};
+
+let filterService = Cc["@mozilla.org/messenger/services/filters;1"]
+                      .getService(Ci.nsIMsgFilterService);
+filterService.addCustomTerm(gCustomSearchTermSubject);
+
+/**
+ * Make sure we open a virtual folder backed by a single underlying folder
+ *  correctly, with a custom search term.
+ */
+function test_virtual_folder_single_load_custom_pred() {
+  let viewWrapper = make_view_wrapper();
+
+  let [folderOne, oneSubjFoo, oneNopers] = make_folder_with_sets([
+    {subject: "foo"}, {}]);
+
+  yield wait_for_message_injection();
+
+  let virtFolder = make_virtual_folder(folderOne,
+                                       {custom: "foo"});
+
+  yield async_view_open(viewWrapper, virtFolder);
+
+  verify_messages_in_view(oneSubjFoo, viewWrapper);
+}
+
+var tests = [
+  test_virtual_folder_single_load_custom_pred,
+];
+
+function run_test() {
+  async_run_tests(tests);
+}
--- a/mailnews/test/resources/messageInjection.js
+++ b/mailnews/test/resources/messageInjection.js
@@ -303,16 +303,19 @@ const SEARCH_TERM_MAP_HELPER = {
   body: Components.interfaces.nsMsgSearchAttrib.Body,
   from: Components.interfaces.nsMsgSearchAttrib.Sender,
   to: Components.interfaces.nsMsgSearchAttrib.To,
   cc: Components.interfaces.nsMsgSearchAttrib.CC,
   recipient: Components.interfaces.nsMsgSearchAttrib.ToOrCC,
   involves: Components.interfaces.nsMsgSearchAttrib.AllAddresses,
   age: Components.interfaces.nsMsgSearchAttrib.AgeInDays,
   tags: Components.interfaces.nsMsgSearchAttrib.Keywords,
+  // If a test uses a custom search term, they must register that term
+  //  with the id "mailnews@mozilla.org#test"
+  custom: Components.interfaces.nsMsgSearchAttrib.Custom,
 };
 
 /**
  * Create and return an empty folder.  If you want to delete this folder
  *  you must call |delete_folder| to kill it!  If you want to rename it, you
  *  must implement a method called rename_folder and then call it.
  *
  * @param [aFolderName] A folder name with no support for hierarchy at this
@@ -418,16 +421,18 @@ function make_virtual_folder(aFolders, a
   let termCreator = Components.classes["@mozilla.org/messenger/searchSession;1"]
                               .createInstance(Ci.nsIMsgSearchSession);
   for each (let [key, val] in Iterator(aSearchDef)) {
     let term = termCreator.createTerm();
     let value = term.value;
     value.str = val;
     term.value = value;
     term.attrib = SEARCH_TERM_MAP_HELPER[key];
+    if (term.attrib == Components.interfaces.nsMsgSearchAttrib.Custom)
+      term.customId = "mailnews@mozilla.org#test";
     term.op = Components.interfaces.nsMsgSearchOp.Contains;
     term.booleanAnd = Boolean(aBooleanAnd);
     terms.push(term);
   }
   // create an ALL case if we didn't add any terms
   if (terms.length == 0) {
     let term = termCreator.createTerm();
     term.matchAll = true;