diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /comm/mailnews/search/test/unit | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
18 files changed, 3659 insertions, 0 deletions
diff --git a/comm/mailnews/search/test/unit/head_mailbase.js b/comm/mailnews/search/test/unit/head_mailbase.js new file mode 100644 index 0000000000..9f37623291 --- /dev/null +++ b/comm/mailnews/search/test/unit/head_mailbase.js @@ -0,0 +1,23 @@ +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); +var { XPCOMUtils } = ChromeUtils.importESModule( + "resource://gre/modules/XPCOMUtils.sys.mjs" +); +var { mailTestUtils } = ChromeUtils.import( + "resource://testing-common/mailnews/MailTestUtils.jsm" +); +var { localAccountUtils } = ChromeUtils.import( + "resource://testing-common/mailnews/LocalAccountUtils.jsm" +); + +var CC = Components.Constructor; + +// Ensure the profile directory is set up +do_get_profile(); + +var gDEPTH = "../../../../"; + +registerCleanupFunction(function () { + load(gDEPTH + "mailnews/resources/mailShutdown.js"); +}); diff --git a/comm/mailnews/search/test/unit/test_base64_decoding.js b/comm/mailnews/search/test/unit/test_base64_decoding.js new file mode 100644 index 0000000000..e0f7ddd94d --- /dev/null +++ b/comm/mailnews/search/test/unit/test_base64_decoding.js @@ -0,0 +1,94 @@ +/* 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 that we do not crash when loading the email bodySearchCrash, +// which was fixed in bug 465805 + +/* import-globals-from ../../../test/resources/searchTestUtils.js */ +load("../../../resources/searchTestUtils.js"); + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); + +var Contains = Ci.nsMsgSearchOp.Contains; +var Body = Ci.nsMsgSearchAttrib.Body; + +var Files = [ + "../../../data/bugmail1", + "../../../data/bodySearchCrash", // Test for bug 465805. + "../../../data/base64-with-whitespace.eml", // Test for bug 1487421. +]; + +var Tests = [ + { + // this number appears in bugmail1 + value: "432710", + attrib: Body, + op: Contains, + count: 1, + }, + { + // this appears in base64-with-whitespace.eml + value: "abcdefghijklmnopqrstuvwxyz", + attrib: Body, + op: Contains, + count: 1, + }, +]; + +function run_test() { + // Setup local mail accounts. + localAccountUtils.loadLocalMailAccount(); + + // Get a message into the local filestore. function testBodySearch() continues the testing after the copy. + do_test_pending(); + copyListener.OnStopCopy(null); + return true; +} + +var copyListener = { + OnStartCopy() {}, + OnProgress(aProgress, aProgressMax) {}, + SetMessageKey(aKey) {}, + SetMessageId(aMessageId) {}, + OnStopCopy(aStatus) { + let fileName = Files.shift(); + if (fileName) { + let file = do_get_file(fileName); + MailServices.copy.copyFileMessage( + file, + localAccountUtils.inboxFolder, + null, + false, + 0, + "", + copyListener, + null + ); + } else { + testBodySearch(); + } + }, +}; + +// Runs at completion of copy + +// process each test from queue, calls itself upon completion of each search +function testBodySearch() { + print("Test Body Search"); + var test = Tests.shift(); + if (test) { + new TestSearch( + localAccountUtils.inboxFolder, + test.value, + test.attrib, + test.op, + test.count, + testBodySearch + ); + } else { + do_test_finished(); + } +} diff --git a/comm/mailnews/search/test/unit/test_bug366491.js b/comm/mailnews/search/test/unit/test_bug366491.js new file mode 100644 index 0000000000..774e8932a3 --- /dev/null +++ b/comm/mailnews/search/test/unit/test_bug366491.js @@ -0,0 +1,110 @@ +/* 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 return of junk percent from bayesian filter + +// main setup + +// only needed during debug +// do_import_script("mailnews/extensions/bayesian-spam-filter/test/resources/trainingfile.js"); + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); + +// local constants +var kUnclassified = MailServices.junk.UNCLASSIFIED; +var kJunk = MailServices.junk.JUNK; +var kGood = MailServices.junk.GOOD; + +/* + * This test is not intended to check the spam calculations, + * but only that the junk percent is transmitted (particularly + * for intermediate values). The test + * junkPercent values below were calculated by the plugin, + * not indepedently verified. + */ + +var tests = [ + { + fileName: "ham2.eml", + junkPercent: 8, + }, + { + fileName: "spam2.eml", + junkPercent: 81, + }, +]; + +var emails = [ + { + fileName: "ham1.eml", + classification: kGood, + }, + { + fileName: "spam1.eml", + classification: kJunk, + }, +]; + +// main test +function run_test() { + localAccountUtils.loadLocalMailAccount(); + do_test_pending(); + doTestingListener.onMessageClassified(null, null, null); + return true; +} + +var haveClassification = false; +var doTestingListener = { + onMessageClassified(aMsgURI, aClassification, aJunkPercent) { + // Do we have more training emails? If so, train + var email = emails.shift(); + if (email) { + MailServices.junk.setMessageClassification( + getSpec(email.fileName), + kUnclassified, + email.classification, + null, + doTestingListener + ); + return; + } + + if (!aMsgURI) { + // Ignore end of batch. + return; + } + + // Have we completed a classification? If so, test + if (haveClassification) { + let test = tests.shift(); + Assert.equal(getSpec(test.fileName), aMsgURI); + Assert.equal(test.junkPercent, aJunkPercent); + } + + // Do we have more classifications to do? Then classify the first one. + if (tests.length) { + haveClassification = true; + MailServices.junk.classifyMessage( + getSpec(tests[0].fileName), + null, + doTestingListener + ); + } else { + do_test_finished(); + } + }, +}; + +// helper functions + +function getSpec(aFileName) { + var file = do_get_file( + "../../../extensions/bayesian-spam-filter/test/unit/resources/" + aFileName + ); + var uri = Services.io.newFileURI(file).QueryInterface(Ci.nsIURL); + uri = uri.mutate().setQuery("type=application/x-message-display").finalize(); + return uri.spec; +} diff --git a/comm/mailnews/search/test/unit/test_bug404489.js b/comm/mailnews/search/test/unit/test_bug404489.js new file mode 100644 index 0000000000..93ae2aac3c --- /dev/null +++ b/comm/mailnews/search/test/unit/test_bug404489.js @@ -0,0 +1,202 @@ +/* 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 that custom headers like "Sender" work (bug 404489) + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); + +var Contains = Ci.nsMsgSearchOp.Contains; +var gArrayHdrs = ["X-Bugzilla-Who", "Sender"]; +var gFirstHeader = Ci.nsMsgSearchAttrib.OtherHeader + 1; +var fileName = "../../../data/SenderHeader"; + +var Tests = [ + /* test header: + X-Bugzilla-Who: bugmail@example.org + + This just shows that normal custom headers work + */ + { + testValue: "bugmail", + attrib: gFirstHeader, + op: Contains, + count: 1, + }, + { + testValue: "ThisIsNotThere", + attrib: gFirstHeader, + op: Contains, + count: 0, + }, + /* test header: + Sender: iamthesender@example.com + + This is the main fix of bug 404489, that we can use Sender as a header + */ + { + testValue: "iamthesender", + attrib: gFirstHeader + 1, + op: Contains, + count: 1, + }, + /* test header: + From: bugzilla-daemon@mozilla.invalid + + Here we show that the "From" header does not fire tests for the + "Sender" arbitrary headers, but does fire the standard test + for nsMsgSenderAttrib.Sender + */ + { + testValue: "bugzilla", + attrib: gFirstHeader + 1, + op: Contains, + count: 0, + }, + { + testValue: "bugzilla", + attrib: Ci.nsMsgSearchAttrib.Sender, + op: Contains, + count: 1, + }, +]; + +function run_test() { + localAccountUtils.loadLocalMailAccount(); + + // add the custom headers into the preferences file, ":" delimited + + var hdrs; + if (gArrayHdrs.length == 1) { + hdrs = gArrayHdrs; + } else { + hdrs = gArrayHdrs.join(": "); + } + Services.prefs.setCharPref("mailnews.customHeaders", hdrs); + + // Get a message into the local filestore. function continue_test() continues the testing after the copy. + do_test_pending(); + var file = do_get_file(fileName); + MailServices.copy.copyFileMessage( + file, + localAccountUtils.inboxFolder, + null, + false, + 0, + "", + copyListener, + null + ); + return true; +} + +var copyListener = { + OnStartCopy() {}, + OnProgress(aProgress, aProgressMax) {}, + SetMessageKey(aKey) {}, + SetMessageId(aMessageId) {}, + OnStopCopy(aStatus) { + continue_test(); + }, +}; + +// Runs at completion of each copy +// process each test from queue, calls itself upon completion of each search +function continue_test() { + var test = Tests.shift(); + if (test) { + new TestSearchx( + localAccountUtils.inboxFolder, + test.testValue, + test.attrib, + test.op, + test.count, + continue_test + ); + } else { + do_test_finished(); + } +} + +/* + * TestSearchx: Class to test number of search hits + * + * @param aFolder: the folder to search + * @param aValue: value used for the search + * The interpretation of aValue depends on aAttrib. It + * defaults to string, but for certain attributes other + * types are used. + * WARNING: not all attributes have been tested. + * + * @param aAttrib: attribute for the search (Ci.nsMsgSearchAttrib.Size, etc.) + * @param aOp: operation for the search (Ci.nsMsgSearchOp.Contains, etc.) + * @param aHitCount: expected number of search hits + * @param onDone: function to call on completion of search + * + */ + +function TestSearchx(aFolder, aValue, aAttrib, aOp, aHitCount, onDone) { + var searchListener = { + onSearchHit(dbHdr, folder) { + hitCount++; + }, + onSearchDone(status) { + print("Finished search does " + aHitCount + " equal " + hitCount + "?"); + searchSession = null; + Assert.equal(aHitCount, hitCount); + if (onDone) { + onDone(); + } + }, + onNewSearch() { + hitCount = 0; + }, + }; + + // define and initiate the search session + + var hitCount; + var searchSession = Cc[ + "@mozilla.org/messenger/searchSession;1" + ].createInstance(Ci.nsIMsgSearchSession); + searchSession.addScopeTerm(Ci.nsMsgSearchScope.offlineMail, aFolder); + var searchTerm = searchSession.createTerm(); + searchTerm.attrib = aAttrib; + + var value = searchTerm.value; + // This is tricky - value.attrib must be set before actual values + value.attrib = aAttrib; + if (aAttrib == Ci.nsMsgSearchAttrib.JunkPercent) { + value.junkPercent = aValue; + } else if (aAttrib == Ci.nsMsgSearchAttrib.Priority) { + value.priority = aValue; + } else if (aAttrib == Ci.nsMsgSearchAttrib.Date) { + value.date = aValue; + } else if (aAttrib == Ci.nsMsgSearchAttrib.MsgStatus) { + value.status = aValue; + } else if (aAttrib == Ci.nsMsgSearchAttrib.MessageKey) { + value.msgKey = aValue; + } else if (aAttrib == Ci.nsMsgSearchAttrib.Size) { + value.size = aValue; + } else if (aAttrib == Ci.nsMsgSearchAttrib.AgeInDays) { + value.age = aValue; + } else if (aAttrib == Ci.nsMsgSearchAttrib.JunkStatus) { + value.junkStatus = aValue; + } else if (aAttrib == Ci.nsMsgSearchAttrib.HasAttachmentStatus) { + value.status = Ci.nsMsgMessageFlags.Attachment; + } else { + value.str = aValue; + } + searchTerm.value = value; + if (aAttrib > Ci.nsMsgSearchAttrib.OtherHeader) { + searchTerm.arbitraryHeader = + gArrayHdrs[aAttrib - 1 - Ci.nsMsgSearchAttrib.OtherHeader]; + } + searchTerm.op = aOp; + searchTerm.booleanAnd = false; + searchSession.appendTerm(searchTerm); + searchSession.registerListener(searchListener); + searchSession.search(null); +} diff --git a/comm/mailnews/search/test/unit/test_copyThenMoveManual.js b/comm/mailnews/search/test/unit/test_copyThenMoveManual.js new file mode 100644 index 0000000000..ef34aeb3ca --- /dev/null +++ b/comm/mailnews/search/test/unit/test_copyThenMoveManual.js @@ -0,0 +1,116 @@ +/* + * This file tests copy followed by a move in a single filter. + * Tests fix from bug 448337. + * + * Original author: Kent James <kent@caspia.com> + */ + +/* import-globals-from ../../../test/resources/POP3pump.js */ +load("../../../resources/POP3pump.js"); + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); +const { PromiseTestUtils } = ChromeUtils.import( + "resource://testing-common/mailnews/PromiseTestUtils.jsm" +); + +var gFiles = ["../../../data/bugmail1"]; +var gCopyFolder; +var gMoveFolder; +var gFilter; // the test filter +var gFilterList; +var gTestArray = [ + function createFilters() { + // setup manual copy then move mail filters on the inbox + gFilterList = localAccountUtils.incomingServer.getFilterList(null); + gFilter = gFilterList.createFilter("copyThenMoveAll"); + let searchTerm = gFilter.createTerm(); + searchTerm.matchAll = true; + gFilter.appendTerm(searchTerm); + let copyAction = gFilter.createAction(); + copyAction.type = Ci.nsMsgFilterAction.CopyToFolder; + copyAction.targetFolderUri = gCopyFolder.URI; + gFilter.appendAction(copyAction); + let moveAction = gFilter.createAction(); + moveAction.type = Ci.nsMsgFilterAction.MoveToFolder; + moveAction.targetFolderUri = gMoveFolder.URI; + gFilter.appendAction(moveAction); + gFilter.enabled = true; + gFilter.filterType = Ci.nsMsgFilterType.Manual; + gFilterList.insertFilterAt(0, gFilter); + }, + // just get a message into the local folder + async function getLocalMessages1() { + gPOP3Pump.files = gFiles; + await gPOP3Pump.run(); + }, + // test applying filters to a message header + async function applyFilters() { + let promiseFolderEvent = PromiseTestUtils.promiseFolderEvent( + localAccountUtils.inboxFolder, + "DeleteOrMoveMsgCompleted" + ); + MailServices.filters.applyFilters( + Ci.nsMsgFilterType.Manual, + [localAccountUtils.inboxFolder.firstNewMessage], + localAccountUtils.inboxFolder, + null + ); + await promiseFolderEvent; + }, + function verifyFolders1() { + // Copy and Move should each now have 1 message in them. + Assert.equal(folderCount(gCopyFolder), 1); + Assert.equal(folderCount(gMoveFolder), 1); + // the local inbox folder should now be empty, since the second + // operation was a move + Assert.equal(folderCount(localAccountUtils.inboxFolder), 0); + }, + // just get a message into the local folder + async function getLocalMessages2() { + gPOP3Pump.files = gFiles; + await gPOP3Pump.run(); + }, + // use the alternate call into the filter service + async function applyFiltersToFolders() { + let folders = [localAccountUtils.inboxFolder]; + let promiseFolderEvent = PromiseTestUtils.promiseFolderEvent( + localAccountUtils.inboxFolder, + "DeleteOrMoveMsgCompleted" + ); + MailServices.filters.applyFiltersToFolders(gFilterList, folders, null); + await promiseFolderEvent; + }, + function verifyFolders2() { + // Copy and Move should each now have 2 message in them. + Assert.equal(folderCount(gCopyFolder), 2); + Assert.equal(folderCount(gMoveFolder), 2); + // the local inbox folder should now be empty, since the second + // operation was a move + Assert.equal(folderCount(localAccountUtils.inboxFolder), 0); + }, + function endTest() { + // Cleanup, null out everything, close all cached connections and stop the + // server + dump(" Exiting mail tests\n"); + gPOP3Pump = null; + }, +]; + +function folderCount(folder) { + return [...folder.msgDatabase.enumerateMessages()].length; +} + +function run_test() { + if (!localAccountUtils.inboxFolder) { + localAccountUtils.loadLocalMailAccount(); + } + + gCopyFolder = localAccountUtils.rootFolder.createLocalSubfolder("CopyFolder"); + gMoveFolder = localAccountUtils.rootFolder.createLocalSubfolder("MoveFolder"); + + gTestArray.forEach(x => add_task(x)); + + run_next_test(); +} diff --git a/comm/mailnews/search/test/unit/test_junkWhitelisting.js b/comm/mailnews/search/test/unit/test_junkWhitelisting.js new file mode 100644 index 0000000000..9263de68a2 --- /dev/null +++ b/comm/mailnews/search/test/unit/test_junkWhitelisting.js @@ -0,0 +1,204 @@ +/* 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/. */ + +/* + * Testing of junk whitelisting + */ + +// add address book setup +/* import-globals-from ../../../test/resources/abSetup.js */ +load("../../../resources/abSetup.js"); + +// add fake POP3 server driver +/* import-globals-from ../../../test/resources/POP3pump.js */ +load("../../../resources/POP3pump.js"); + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); + +/* + * The address available in the test address book is "PrimaryEmail1@test.invalid" + * Test emails may also include the address "invalid@example.com" + * + * Map of test email contents: (P is "Prim...", I is "inva.." address) + * + * Index Bugmail# From + * 0 1 P + * 1 3 I + * + */ + +// indices into hdrs[] of email by domain +var kDomainTest = 0; +var kDomainExample = 1; + +var Files = ["../../../data/bugmail1", "../../../data/bugmail3"]; + +var hdrs = []; + +function run_test() { + loadABFile( + "../../../addrbook/test/unit/data/cardForEmail", + kPABData.fileName + ); + + do_test_pending(); + + // kick off copying + gPOP3Pump.files = Files; + gPOP3Pump.onDone = continueTest; + gPOP3Pump.run(); +} + +function continueTest() { + // get the message headers + for (let header of localAccountUtils.inboxFolder.messages) { + hdrs.push(header); + } + + // check with spam properties set on the local server + doChecks(localAccountUtils.incomingServer); + + // Free our globals + hdrs = null; + gPOP3Pump = null; + do_test_finished(); +} + +function doChecks(server) { + let spamSettings = server.spamSettings; + + // default is to use the whitelist + Assert.ok(spamSettings.useWhiteList); + + // check email with the address PrimaryEmail1@test.invalid + Assert.ok(spamSettings.checkWhiteList(hdrs[kDomainTest])); + + // check email without the address + Assert.ok(!spamSettings.checkWhiteList(hdrs[kDomainExample])); + + // + // check changes in server-level settings. Although the spamSettings object + // has methods to set these, those methods are not persistent (which seems + // strange). You need to set the actual preference, and call initialize on + // spam settings, to get the settings to be saved persistently and stick, then + // be recalled into the program. So that's the way that I will test it. + // + + // disable whitelisting + server.setBoolValue("useWhiteList", false); + spamSettings.initialize(server); + + // check that the change was propagated to spamSettings + Assert.ok(!spamSettings.useWhiteList); + + // and affects whitelisting calculationss + Assert.ok(!spamSettings.checkWhiteList(hdrs[kDomainTest])); + + // re-enable whitelisting + server.setBoolValue("useWhiteList", true); + spamSettings.initialize(server); + Assert.ok(spamSettings.checkWhiteList(hdrs[kDomainTest])); + + // Set an empty white list. + // To really empty this, I have to change the default value as well + Services.prefs.setCharPref("mail.server.default.whiteListAbURI", ""); + server.setCharValue("whiteListAbURI", ""); + spamSettings.initialize(server); + Assert.ok(!spamSettings.checkWhiteList(hdrs[kDomainTest])); + + // add a trusted domain. This is a global preference + Services.prefs.setCharPref("mail.trusteddomains", "example.com"); + spamSettings.initialize(server); + + // check email with the address invalid@example.com, a trusted domain + Assert.ok(spamSettings.checkWhiteList(hdrs[kDomainExample])); + + // check email without the address + Assert.ok(!spamSettings.checkWhiteList(hdrs[kDomainTest])); + + // disable the trusted domain + Services.prefs.setCharPref("mail.trusteddomains", ""); + spamSettings.initialize(server); + Assert.ok(!spamSettings.checkWhiteList(hdrs[kDomainExample])); + + // add back the Personal Address Book + server.setCharValue("whiteListAbURI", kPABData.URI); + spamSettings.initialize(server); + Assert.ok(spamSettings.checkWhiteList(hdrs[kDomainTest])); + + /* + * tests of whitelist suppression by identity + */ + + // setup + let account = MailServices.accounts.FindAccountForServer(server); + let identity = MailServices.accounts.createIdentity(); + // start with an email that does not match + identity.email = "iAmNotTheSender@test.invalid"; + account.addIdentity(identity); + + // setup account and identify for the deferred-from fake server + let fakeAccount = MailServices.accounts.createAccount(); + fakeAccount.incomingServer = gPOP3Pump.fakeServer; + let fakeIdentity = MailServices.accounts.createIdentity(); + // start with an email that does not match + fakeIdentity.email = "iAmNotTheSender@wrong.invalid"; + fakeAccount.addIdentity(fakeIdentity); + + // gPOP3Pump delivers messages to the local inbox regardless of other + // settings. But because we are testing here one of those other settings, + // let's just pretend that it works like the real POP3 stuff, and set + // the correct setting for deferring. + gPOP3Pump.fakeServer.setCharValue("deferred_to_account", "account1"); + + // suppress whitelisting for sender + server.setBoolValue("inhibitWhiteListingIdentityUser", true); + spamSettings.initialize(server); + // (email does not match yet though) + Assert.ok(spamSettings.checkWhiteList(hdrs[kDomainTest])); + + // add a matching email (mixing case) + identity.email = "PrimaryEMAIL1@test.INVALID"; + spamSettings.initialize(server); + Assert.ok(!spamSettings.checkWhiteList(hdrs[kDomainTest])); + + // remove the matching email + identity.email = "iAmNotTheSender@test.invalid"; + spamSettings.initialize(server); + Assert.ok(spamSettings.checkWhiteList(hdrs[kDomainTest])); + + // add the email to the deferred-from server + fakeIdentity.email = "PrimaryEMAIL1@test.INVALID"; + spamSettings.initialize(server); + Assert.ok(!spamSettings.checkWhiteList(hdrs[kDomainTest])); + + // stop suppressing identity users + server.setBoolValue("inhibitWhiteListingIdentityUser", false); + spamSettings.initialize(server); + Assert.ok(spamSettings.checkWhiteList(hdrs[kDomainTest])); + + // remove the matching email from the fake identity + fakeIdentity.email = "iAmNotTheSender@wrong.invalid"; + + // add a fully non-matching domain to the identity + identity.email = "PrimaryEmail1@wrong.invalid"; + + // suppress whitelist by matching domain + server.setBoolValue("inhibitWhiteListingIdentityDomain", true); + spamSettings.initialize(server); + // but domain still does not match + Assert.ok(spamSettings.checkWhiteList(hdrs[kDomainTest])); + + // add a matching email to the identity, in the domain (mixing case) + identity.email = "iAmNotTheSender@TEST.invalid"; + spamSettings.initialize(server); + Assert.ok(!spamSettings.checkWhiteList(hdrs[kDomainTest])); + + // stop suppressing whitelist by domain + server.setBoolValue("inhibitWhiteListingIdentityDomain", false); + spamSettings.initialize(server); + Assert.ok(spamSettings.checkWhiteList(hdrs[kDomainTest])); +} diff --git a/comm/mailnews/search/test/unit/test_quarantineFilterMove.js b/comm/mailnews/search/test/unit/test_quarantineFilterMove.js new file mode 100644 index 0000000000..853a3980f4 --- /dev/null +++ b/comm/mailnews/search/test/unit/test_quarantineFilterMove.js @@ -0,0 +1,181 @@ +/* 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 message moves with filter and quarantine enabled per bug 582918. + * It then tests that subsequent moves of the filtered messages work. + * + * adapted from test_copyThenMoveManual.js + */ + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); +const { PromiseTestUtils } = ChromeUtils.import( + "resource://testing-common/mailnews/PromiseTestUtils.jsm" +); + +/* import-globals-from ../../../test/resources/POP3pump.js */ +load("../../../resources/POP3pump.js"); + +var gFiles = ["../../../data/bugmail1", "../../../data/bugmail10"]; + +var gMoveFolder, gMoveFolder2; +var gFilter; // the test filter +var gFilterList; +var gTestArray = [ + function createFilters() { + gFilterList = gPOP3Pump.fakeServer.getFilterList(null); + gFilter = gFilterList.createFilter("MoveAll"); + let searchTerm = gFilter.createTerm(); + searchTerm.matchAll = true; + gFilter.appendTerm(searchTerm); + let moveAction = gFilter.createAction(); + moveAction.type = Ci.nsMsgFilterAction.MoveToFolder; + moveAction.targetFolderUri = gMoveFolder.URI; + gFilter.appendAction(moveAction); + gFilter.enabled = true; + gFilter.filterType = Ci.nsMsgFilterType.InboxRule; + gFilterList.insertFilterAt(0, gFilter); + }, + // just get a message into the local folder + async function getLocalMessages1() { + gPOP3Pump.files = gFiles; + let promise1 = PromiseTestUtils.promiseFolderNotification( + gMoveFolder, + "msgsClassified" + ); + let promise2 = gPOP3Pump.run(); + await Promise.all([promise1, promise2]); + }, + async function verifyFolders1() { + Assert.equal(folderCount(gMoveFolder), 2); + // the local inbox folder should now be empty, since the second + // operation was a move + Assert.equal(folderCount(localAccountUtils.inboxFolder), 0); + + let msgs = [...gMoveFolder.msgDatabase.enumerateMessages()]; + let firstMsgHdr = msgs[0]; + let secondMsgHdr = msgs[1]; + // Check that the messages have content + let messageContent = await getContentFromMessage(firstMsgHdr); + Assert.ok( + messageContent.includes("Some User <bugmail@example.org> changed") + ); + messageContent = await getContentFromMessage(secondMsgHdr); + Assert.ok( + messageContent.includes( + "https://bugzilla.mozilla.org/show_bug.cgi?id=436880" + ) + ); + }, + async function copyMovedMessages() { + let msgs = [...gMoveFolder.msgDatabase.enumerateMessages()]; + let firstMsgHdr = msgs[0]; + let secondMsgHdr = msgs[1]; + let promiseCopyListener = new PromiseTestUtils.PromiseCopyListener(); + MailServices.copy.copyMessages( + gMoveFolder, + [firstMsgHdr, secondMsgHdr], + gMoveFolder2, + false, + promiseCopyListener, + null, + false + ); + let promiseMoveMsg = PromiseTestUtils.promiseFolderEvent( + gMoveFolder, + "DeleteOrMoveMsgCompleted" + ); + await Promise.all([promiseCopyListener.promise, promiseMoveMsg]); + }, + async function verifyFolders2() { + Assert.equal(folderCount(gMoveFolder2), 2); + + let msgs = [...gMoveFolder2.msgDatabase.enumerateMessages()]; + let firstMsgHdr = msgs[0]; + let secondMsgHdr = msgs[1]; + // Check that the messages have content + let messageContent = await getContentFromMessage(firstMsgHdr); + Assert.ok( + messageContent.includes("Some User <bugmail@example.org> changed") + ); + messageContent = await getContentFromMessage(secondMsgHdr); + Assert.ok( + messageContent.includes( + "https://bugzilla.mozilla.org/show_bug.cgi?id=436880" + ) + ); + }, + function endTest() { + dump("Exiting mail tests\n"); + gPOP3Pump = null; + }, +]; + +function folderCount(folder) { + return [...folder.msgDatabase.enumerateMessages()].length; +} + +function run_test() { + /* may not work in Linux */ + // if ("@mozilla.org/gnome-gconf-service;1" in Cc) + // return; + /**/ + // quarantine messages + Services.prefs.setBoolPref("mailnews.downloadToTempFile", true); + if (!localAccountUtils.inboxFolder) { + localAccountUtils.loadLocalMailAccount(); + } + + gMoveFolder = localAccountUtils.rootFolder.createLocalSubfolder("MoveFolder"); + gMoveFolder2 = + localAccountUtils.rootFolder.createLocalSubfolder("MoveFolder2"); + + gTestArray.forEach(x => add_task(x)); + run_next_test(); +} + +/** + * Get the full message content. + * + * @param aMsgHdr - nsIMsgDBHdr object whose text body will be read. + * @returns {Promise<string>} full message contents. + */ +function getContentFromMessage(aMsgHdr) { + let msgFolder = aMsgHdr.folder; + let msgUri = msgFolder.getUriForMsg(aMsgHdr); + + return new Promise((resolve, reject) => { + let streamListener = { + QueryInterface: ChromeUtils.generateQI(["nsIStreamListener"]), + sis: Cc["@mozilla.org/scriptableinputstream;1"].createInstance( + Ci.nsIScriptableInputStream + ), + content: "", + onDataAvailable(request, inputStream, offset, count) { + this.sis.init(inputStream); + this.content += this.sis.read(count); + }, + onStartRequest(request) {}, + onStopRequest(request, statusCode) { + this.sis.close(); + if (Components.isSuccessCode(statusCode)) { + resolve(this.content); + } else { + reject(new Error(statusCode)); + } + }, + }; + MailServices.messageServiceFromURI(msgUri).streamMessage( + msgUri, + streamListener, + null, + null, + false, + "", + false + ); + }); +} diff --git a/comm/mailnews/search/test/unit/test_search.js b/comm/mailnews/search/test/unit/test_search.js new file mode 100644 index 0000000000..98e8874fd3 --- /dev/null +++ b/comm/mailnews/search/test/unit/test_search.js @@ -0,0 +1,623 @@ +/* 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/. */ + +/* + * Testing of general mail search features. + * + * This tests some search attributes not tested by other specific tests, + * e.g., test_searchTag.js or test_searchJunk.js + */ +/* import-globals-from ../../../test/resources/searchTestUtils.js */ +load("../../../resources/searchTestUtils.js"); + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); + +var Isnt = Ci.nsMsgSearchOp.Isnt; +var Is = Ci.nsMsgSearchOp.Is; +var Contains = Ci.nsMsgSearchOp.Contains; +var DoesntContain = Ci.nsMsgSearchOp.DoesntContain; +var BeginsWith = Ci.nsMsgSearchOp.BeginsWith; +var EndsWith = Ci.nsMsgSearchOp.EndsWith; +var IsBefore = Ci.nsMsgSearchOp.IsBefore; // control entry not enabled +var IsAfter = Ci.nsMsgSearchOp.IsAfter; +var IsHigherThan = Ci.nsMsgSearchOp.IsHigherThan; +var IsLowerThan = Ci.nsMsgSearchOp.IsLowerThan; + +var OtherHeader = Ci.nsMsgSearchAttrib.OtherHeader; +var From = Ci.nsMsgSearchAttrib.Sender; +var Subject = Ci.nsMsgSearchAttrib.Subject; +var Priority = Ci.nsMsgSearchAttrib.Priority; +var SDate = Ci.nsMsgSearchAttrib.Date; + +var Tests = [ + // test the To: header + { + testString: "PrimaryEmail1@test.invalid", + testAttribute: From, + op: Is, + count: 1, + }, + { + testString: "PrimaryEmail1@test.invalid", + testAttribute: From, + op: Isnt, + count: 0, + }, + { + testString: "PrimaryEmail", + testAttribute: From, + op: BeginsWith, + count: 1, + }, + { + testString: "invalid", + testAttribute: From, + op: BeginsWith, + count: 0, + }, + { + testString: "invalid", + testAttribute: From, + op: EndsWith, + count: 1, + }, + { + testString: "Primary", + testAttribute: From, + op: EndsWith, + count: 0, + }, + { + testString: "QAContact", + testAttribute: OtherHeader, + op: BeginsWith, + count: 1, + }, + { + testString: "filters", + testAttribute: OtherHeader, + op: BeginsWith, + count: 0, + }, + { + testString: "mail.bugs", + testAttribute: OtherHeader, + op: EndsWith, + count: 1, + }, + { + testString: "QAContact", + testAttribute: OtherHeader, + op: EndsWith, + count: 0, + }, + { + testString: "QAcontact filters@mail.bugs", + testAttribute: OtherHeader, + op: Is, + count: 1, + }, + { + testString: "filters@mail.bugs", + testAttribute: OtherHeader, + op: Is, + count: 0, + }, + { + testString: "QAcontact filters@mail.bugs", + testAttribute: OtherHeader, + op: Isnt, + count: 0, + }, + { + testString: "QAcontact", + testAttribute: OtherHeader, + op: Isnt, + count: 1, + }, + { + testString: "filters", + testAttribute: OtherHeader, + op: Contains, + count: 1, + }, + { + testString: "foobar", + testAttribute: OtherHeader, + op: Contains, + count: 0, + }, + // test header with multiple occurrences + { + testString: "one value", + testAttribute: OtherHeader, + op: Is, + customHeader: "X-Duplicated-Header", + count: 1, + }, + { + testString: "second", + testAttribute: OtherHeader, + op: Is, + customHeader: "X-Duplicated-Header", + count: 1, + }, + { + testString: "third value for test purposes", + testAttribute: OtherHeader, + op: Is, + customHeader: "X-Duplicated-Header", + count: 1, + }, + { + testString: "multiline value that needs to be handled.", + testAttribute: OtherHeader, + op: Is, + customHeader: "X-Duplicated-Header", + count: 1, + }, + { + testString: "one value", + testAttribute: OtherHeader, + op: Isnt, + customHeader: "X-Duplicated-Header", + count: 0, + }, + { + testString: "second", + testAttribute: OtherHeader, + op: Isnt, + customHeader: "X-Duplicated-Header", + count: 0, + }, + { + testString: "third value for test purposes", + testAttribute: OtherHeader, + op: Isnt, + customHeader: "X-Duplicated-Header", + count: 0, + }, + { + testString: "multiline value that needs to be handled.", + testAttribute: OtherHeader, + op: Isnt, + customHeader: "X-Duplicated-Header", + count: 0, + }, + { + testString: "one", + testAttribute: OtherHeader, + op: Contains, + customHeader: "X-Duplicated-Header", + count: 1, + }, + { + testString: "second", + testAttribute: OtherHeader, + op: Contains, + customHeader: "X-Duplicated-Header", + count: 1, + }, + { + testString: "purposes", + testAttribute: OtherHeader, + op: Contains, + customHeader: "X-Duplicated-Header", + count: 1, + }, + { + testString: "value", + testAttribute: OtherHeader, + op: Contains, + customHeader: "X-Duplicated-Header", + count: 1, + }, + { + testString: "that needs to be", + testAttribute: OtherHeader, + op: Contains, + customHeader: "X-Duplicated-Header", + count: 1, + }, + { + testString: "fifth", + testAttribute: OtherHeader, + op: Contains, + customHeader: "X-Duplicated-Header", + count: 1, + }, + { + testString: "is the end my", + testAttribute: OtherHeader, + op: Contains, + customHeader: "X-Duplicated-Header", + count: 1, + }, + { + testString: "the end", + testAttribute: OtherHeader, + op: EndsWith, + customHeader: "X-Duplicated-Header", + count: 0, + }, + { + testString: "handled.", + testAttribute: OtherHeader, + op: EndsWith, + customHeader: "X-Duplicated-Header", + count: 1, + }, + { + testString: "one value", + testAttribute: OtherHeader, + op: EndsWith, + customHeader: "X-Duplicated-Header", + count: 1, + }, + { + testString: "third", + testAttribute: OtherHeader, + op: BeginsWith, + customHeader: "X-Duplicated-Header", + count: 1, + }, + { + testString: "This is", + testAttribute: OtherHeader, + op: BeginsWith, + customHeader: "X-Duplicated-Header", + count: 1, + }, + + { + testString: "nothing", + testAttribute: OtherHeader, + op: Contains, + customHeader: "X-Duplicated-Header", + count: 0, + }, + { + testString: "nothing", + testAttribute: OtherHeader, + op: DoesntContain, + customHeader: "X-Duplicated-Header", + count: 1, + }, + { + testString: "this header tests DB string properties", + testAttribute: OtherHeader, + op: Is, + customHeader: "X-Duplicated-Header-DB", + count: 1, + }, + { + testString: "which can be handled", + testAttribute: OtherHeader, + op: Is, + customHeader: "X-Duplicated-Header-DB", + count: 1, + }, + { + testString: "differently than X-Duplicated-Header, so better test it", + testAttribute: OtherHeader, + op: Is, + customHeader: "X-Duplicated-Header-DB", + count: 1, + }, + { + testString: "this header tests DB string properties", + testAttribute: OtherHeader, + op: Isnt, + customHeader: "X-Duplicated-Header-DB", + count: 0, + }, + { + testString: "which can be handled", + testAttribute: OtherHeader, + op: Isnt, + customHeader: "X-Duplicated-Header-DB", + count: 0, + }, + { + testString: "differently than X-Duplicated-Header, so better test it", + testAttribute: OtherHeader, + op: Isnt, + customHeader: "X-Duplicated-Header-DB", + count: 0, + }, + { + testString: "than X-Duplicated-Header,", + testAttribute: OtherHeader, + op: Contains, + customHeader: "X-Duplicated-Header-DB", + count: 1, + }, + { + testString: "than X-Duplicated-Header, so", + testAttribute: OtherHeader, + op: DoesntContain, + customHeader: "X-Duplicated-Header-DB", + count: 0, + }, + // test accumulation of received header + { + // only in first received + testString: "caspiaco", + testAttribute: OtherHeader, + op: Contains, + customHeader: "Received", + count: 1, + }, + { + // only in second + testString: "webapp01.sj.mozilla.com", + testAttribute: OtherHeader, + op: Contains, + customHeader: "received", + count: 1, + }, + { + // in neither + testString: "not there", + testAttribute: OtherHeader, + op: Contains, + customHeader: "received", + count: 0, + }, + { + // not on first line of received + testString: "m47LtAFJ007547", + testAttribute: OtherHeader, + op: Contains, + customHeader: "received", + count: 1, + }, + // test multiple line arbitrary headers + { + // in the first line + testString: "SpamAssassin 3.2.3", + testAttribute: OtherHeader, + op: Contains, + customHeader: "X-Spam-Checker-Version", + count: 1, + }, + { + // in the second line + testString: "host29.example.com", + testAttribute: OtherHeader, + op: Contains, + customHeader: "X-Spam-Checker-Version", + count: 1, + }, + { + // spans two lines with space + testString: "on host29.example.com", + testAttribute: OtherHeader, + op: Contains, + customHeader: "X-Spam-Checker-Version", + count: 1, + }, + // subject spanning several lines + { + // on the first line + testString: "A filter will", + testAttribute: Subject, + op: Contains, + count: 1, + }, + { + testString: "I do not exist", + testAttribute: Subject, + op: Contains, + count: 0, + }, + { + // on the second line + testString: "this message", + testAttribute: Subject, + op: Contains, + count: 1, + }, + { + // spanning second and third line + testString: "over many", + testAttribute: Subject, + op: Contains, + count: 1, + }, + // tests of custom headers db values + { + testString: "a one line header", + dbHeader: "oneliner", + }, + { + testString: "a two line header", + dbHeader: "twoliner", + }, + { + testString: "a three line header with lotsa space and tabs", + dbHeader: "threeliner", + }, + { + testString: "I have no space", + dbHeader: "nospace", + }, + { + testString: "too much space", + dbHeader: "withspace", + }, + // tests of custom db headers in a search + { + testString: "one line", + testAttribute: OtherHeader, + op: Contains, + customHeader: "oneliner", + count: 1, + }, + { + testString: "two line header", + testAttribute: OtherHeader, + op: Contains, + customHeader: "twoliner", + count: 1, + }, + { + testString: "three line header with lotsa", + testAttribute: OtherHeader, + op: Contains, + customHeader: "threeliner", + count: 1, + }, + { + testString: "I have no space", + testAttribute: OtherHeader, + op: Contains, + customHeader: "nospace", + count: 1, + }, + { + testString: "too much space", + testAttribute: OtherHeader, + op: Contains, + customHeader: "withspace", + count: 1, + }, + // test for priority + { + testString: Ci.nsMsgPriority.lowest, + testAttribute: Priority, + op: IsHigherThan, + count: 1, + }, + { + testString: Ci.nsMsgPriority.low, + testAttribute: Priority, + op: Is, + count: 1, + }, + { + testString: Ci.nsMsgPriority.normal, + testAttribute: Priority, + op: IsLowerThan, + count: 1, + }, + { + testString: Ci.nsMsgPriority.lowest, + testAttribute: Priority, + op: Isnt, + count: 1, + }, + { + testString: Ci.nsMsgPriority.low, + testAttribute: Priority, + op: Isnt, + count: 0, + }, + + // tests of Date header + // The internal value of date in the search is PRTime (nanoseconds since Epoch). + // Date().getTime() returns milliseconds since Epoch. + // The dates used here are tailored for the ../../../data/bugmail12 message. + { + testString: new Date("Wed, 7 May 2008 14:55:10 -0700").getTime() * 1000, + testAttribute: SDate, + op: Is, + count: 1, + }, + { + testString: new Date("Thu, 8 May 2008 14:55:10 -0700").getTime() * 1000, + testAttribute: SDate, + op: IsBefore, + count: 1, + }, + { + testString: new Date("Tue, 6 May 2008 14:55:10 -0700").getTime() * 1000, + testAttribute: SDate, + op: IsAfter, + count: 1, + }, + { + testString: new Date("Tue, 6 May 2008 14:55:10 -0700").getTime() * 1000, + testAttribute: SDate, + op: Isnt, + count: 1, + }, + { + // check bug 248808 + testString: new Date("Wed, 7 May 2008 14:55:10 -0700").getTime() * 1000, + testAttribute: SDate, + op: IsBefore, + count: 0, + }, + { + testString: new Date("Wed, 7 May 2008 14:55:10 -0700").getTime() * 1000, + testAttribute: SDate, + op: IsAfter, + count: 0, + }, +]; + +function run_test() { + localAccountUtils.loadLocalMailAccount(); + + var copyListener = { + OnStartCopy() {}, + OnProgress(aProgress, aProgressMax) {}, + SetMessageKey(aKey) {}, + SetMessageId(aMessageId) {}, + OnStopCopy(aStatus) { + testSearch(); + }, + }; + + // set value of headers we want parsed into the db + Services.prefs.setCharPref( + "mailnews.customDBHeaders", + "oneLiner twoLiner threeLiner noSpace withSpace X-Duplicated-Header-DB" + ); + // Get a message into the local filestore. function testSearch() continues + // the testing after the copy. + var bugmail12 = do_get_file("../../../data/bugmail12"); + do_test_pending(); + MailServices.copy.copyFileMessage( + bugmail12, + localAccountUtils.inboxFolder, + null, + false, + 0, + "", + copyListener, + null + ); +} + +// process each test from queue, calls itself upon completion of each search +function testSearch() { + var test = Tests.shift(); + if (test && test.dbHeader) { + // test of a custom db header + dump("testing dbHeader " + test.dbHeader + "\n"); + let customValue = mailTestUtils + .firstMsgHdr(localAccountUtils.inboxFolder) + .getStringProperty(test.dbHeader); + Assert.equal(customValue, test.testString); + do_timeout(0, testSearch); + } else if (test) { + dump("testing for string '" + test.testString + "'\n"); + new TestSearch( + localAccountUtils.inboxFolder, + test.testString, + test.testAttribute, + test.op, + test.count, + testSearch, + null, + test.customHeader ? test.customHeader : "X-Bugzilla-Watch-Reason" + ); + } else { + do_test_finished(); + } +} diff --git a/comm/mailnews/search/test/unit/test_searchAddressInAb.js b/comm/mailnews/search/test/unit/test_searchAddressInAb.js new file mode 100644 index 0000000000..a93f405047 --- /dev/null +++ b/comm/mailnews/search/test/unit/test_searchAddressInAb.js @@ -0,0 +1,337 @@ +/* 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/. */ + +// Testing of to, cc, toorcc in addressbook search features added in bug 187768 +// Added testing of AllAddresses from bug 310359 + +/* import-globals-from ../../../test/resources/searchTestUtils.js */ +load("../../../resources/searchTestUtils.js"); + +// add address book setup +/* import-globals-from ../../../test/resources/abSetup.js */ +load("../../../resources/abSetup.js"); + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); + +var ABUri = kPABData.URI; + +var IsntInAB = Ci.nsMsgSearchOp.IsntInAB; +var IsInAB = Ci.nsMsgSearchOp.IsInAB; +var IsBefore = Ci.nsMsgSearchOp.IsBefore; // control entry that is not enabled +var Is = Ci.nsMsgSearchOp.Is; +var Isnt = Ci.nsMsgSearchOp.Isnt; + +var offlineMail = Ci.nsMsgSearchScope.offlineMail; +var onlineMail = Ci.nsMsgSearchScope.onlineMail; +var offlineMailFilter = Ci.nsMsgSearchScope.offlineMailFilter; +var onlineMailFilter = Ci.nsMsgSearchScope.onlineMailFilter; +var news = Ci.nsMsgSearchScope.news; // control entry that is not enabled + +var Sender = Ci.nsMsgSearchAttrib.Sender; +var To = Ci.nsMsgSearchAttrib.To; +var CCopy = Ci.nsMsgSearchAttrib.CC; +var ToOrCC = Ci.nsMsgSearchAttrib.ToOrCC; +var AllAddresses = Ci.nsMsgSearchAttrib.AllAddresses; +var Keywords = Ci.nsMsgSearchAttrib.Keywords; // control entry that is not enabled + +/* + * The address available in the test address book is "PrimaryEmail1@test.invalid" + * Test emails may also include the address "invalid@example.com" + * + * + * Map of test email contents: (P is "Prim...", I is "inva.." address, N is none) + * + * + * Email From To CC BCC + * 1 P I I N + * 2 P P P N + * 3 I P I N + * 4 I I P N + * 5 P I P N + * 6 I I,P P,I N + * 7 I I I P + * 8 I P P N + * + */ + +var Tests = [ + { + value: ABUri, + attrib: Sender, + op: IsInAB, + count: 3, + }, + { + value: ABUri, + attrib: To, + op: IsInAB, + count: 4, + }, + { + value: ABUri, + attrib: ToOrCC, + op: IsInAB, + count: 6, + }, + { + value: ABUri, + attrib: AllAddresses, + op: IsInAB, + count: 8, + }, + { + value: ABUri, + attrib: CCopy, + op: IsInAB, + count: 5, + }, + { + value: ABUri, + attrib: Sender, + op: IsntInAB, + count: 5, + }, + { + value: ABUri, + attrib: To, + op: IsntInAB, + count: 5, + }, + { + value: ABUri, + attrib: ToOrCC, + op: IsntInAB, + count: 6, + }, + { + value: ABUri, + attrib: AllAddresses, + op: IsntInAB, + count: 7, + }, + { + value: ABUri, + attrib: CCopy, + op: IsntInAB, + count: 4, + }, + { + value: "PrimaryEmail1@test.invalid", + attrib: AllAddresses, + op: Is, + count: 8, + }, + { + value: "PrimaryEmail1@test.invalid", + attrib: AllAddresses, + op: Isnt, + count: 0, + }, + { + value: "invalid@example.com", + attrib: AllAddresses, + op: Is, + count: 7, + }, + { + value: "invalid@example.com", + attrib: AllAddresses, + op: Isnt, + count: 1, + }, + { + value: "PrimaryEmail1@test.invalid", + attrib: ToOrCC, + op: Is, + count: 6, + }, + { + value: "PrimaryEmail1@test.invalid", + attrib: ToOrCC, + op: Isnt, + count: 2, + }, + { + value: "invalid@example.com", + attrib: ToOrCC, + op: Is, + count: 6, + }, + { + value: "invalid@example.com", + attrib: ToOrCC, + op: Isnt, + count: 2, + }, +]; + +var Files = [ + "../../../data/bugmail1", + "../../../data/bugmail2", + "../../../data/bugmail3", + "../../../data/bugmail4", + "../../../data/bugmail5", + "../../../data/bugmail6", + "../../../data/bugmail7", + "../../../data/bugmail8", +]; + +function run_test() { + // Setup local mail accounts. + localAccountUtils.loadLocalMailAccount(); + + loadABFile( + "../../../addrbook/test/unit/data/cardForEmail", + kPABData.fileName + ); + + // test that validity table terms are valid + + // offline mail table + testValidityTable(offlineMail, IsInAB, Sender, true); + testValidityTable(offlineMail, IsInAB, To, true); + testValidityTable(offlineMail, IsInAB, ToOrCC, true); + testValidityTable(offlineMail, IsInAB, AllAddresses, true); + testValidityTable(offlineMail, IsInAB, CCopy, true); + testValidityTable(offlineMail, IsInAB, Keywords, false); + testValidityTable(offlineMail, IsntInAB, Sender, true); + testValidityTable(offlineMail, IsntInAB, To, true); + testValidityTable(offlineMail, IsntInAB, ToOrCC, true); + testValidityTable(offlineMail, IsntInAB, AllAddresses, true); + testValidityTable(offlineMail, IsntInAB, CCopy, true); + testValidityTable(offlineMail, IsntInAB, Keywords, false); + testValidityTable(offlineMail, IsBefore, Sender, false); + testValidityTable(offlineMail, IsBefore, To, false); + testValidityTable(offlineMail, IsBefore, ToOrCC, false); + testValidityTable(offlineMail, IsBefore, AllAddresses, false); + testValidityTable(offlineMail, IsBefore, CCopy, false); + testValidityTable(offlineMail, IsBefore, Keywords, false); + testValidityTable(offlineMail, Is, AllAddresses, true); + testValidityTable(offlineMail, Isnt, AllAddresses, true); + + // offline mail filter table + testValidityTable(offlineMailFilter, IsInAB, Sender, true); + testValidityTable(offlineMailFilter, IsInAB, To, true); + testValidityTable(offlineMailFilter, IsInAB, ToOrCC, true); + testValidityTable(offlineMailFilter, IsInAB, AllAddresses, true); + testValidityTable(offlineMailFilter, IsInAB, CCopy, true); + testValidityTable(offlineMailFilter, IsInAB, Keywords, false); + testValidityTable(offlineMailFilter, IsntInAB, Sender, true); + testValidityTable(offlineMailFilter, IsntInAB, To, true); + testValidityTable(offlineMailFilter, IsntInAB, AllAddresses, true); + testValidityTable(offlineMailFilter, IsntInAB, ToOrCC, true); + testValidityTable(offlineMailFilter, IsntInAB, CCopy, true); + testValidityTable(offlineMailFilter, IsntInAB, Keywords, false); + testValidityTable(offlineMailFilter, IsBefore, Sender, false); + testValidityTable(offlineMailFilter, IsBefore, To, false); + testValidityTable(offlineMailFilter, IsBefore, ToOrCC, false); + testValidityTable(offlineMailFilter, IsBefore, AllAddresses, false); + testValidityTable(offlineMailFilter, IsBefore, CCopy, false); + testValidityTable(offlineMailFilter, IsBefore, Keywords, false); + testValidityTable(offlineMailFilter, Is, AllAddresses, true); + testValidityTable(offlineMailFilter, Isnt, AllAddresses, true); + + // online mail + testValidityTable(onlineMail, IsInAB, Sender, false); + testValidityTable(onlineMail, IsInAB, To, false); + testValidityTable(onlineMail, IsInAB, ToOrCC, false); + testValidityTable(onlineMail, IsInAB, CCopy, false); + testValidityTable(onlineMail, IsInAB, Keywords, false); + testValidityTable(onlineMail, IsntInAB, Sender, false); + testValidityTable(onlineMail, IsntInAB, To, false); + testValidityTable(onlineMail, IsntInAB, ToOrCC, false); + testValidityTable(onlineMail, IsntInAB, CCopy, false); + testValidityTable(onlineMail, IsntInAB, Keywords, false); + testValidityTable(onlineMail, IsBefore, Sender, false); + testValidityTable(onlineMail, IsBefore, To, false); + testValidityTable(onlineMail, IsBefore, ToOrCC, false); + testValidityTable(onlineMail, IsBefore, CCopy, false); + testValidityTable(onlineMail, IsBefore, Keywords, false); + + // online mail filter + testValidityTable(onlineMailFilter, IsInAB, Sender, true); + testValidityTable(onlineMailFilter, IsInAB, To, true); + testValidityTable(onlineMailFilter, IsInAB, ToOrCC, true); + testValidityTable(onlineMailFilter, IsInAB, CCopy, true); + testValidityTable(onlineMailFilter, IsInAB, Keywords, false); + testValidityTable(onlineMailFilter, IsntInAB, Sender, true); + testValidityTable(onlineMailFilter, IsntInAB, To, true); + testValidityTable(onlineMailFilter, IsntInAB, ToOrCC, true); + testValidityTable(onlineMailFilter, IsntInAB, CCopy, true); + testValidityTable(onlineMailFilter, IsntInAB, Keywords, false); + testValidityTable(onlineMailFilter, IsBefore, Sender, false); + testValidityTable(onlineMailFilter, IsBefore, To, false); + testValidityTable(onlineMailFilter, IsBefore, ToOrCC, false); + testValidityTable(onlineMailFilter, IsBefore, CCopy, false); + testValidityTable(onlineMailFilter, IsBefore, Keywords, false); + + // news + testValidityTable(news, IsInAB, Sender, false); + testValidityTable(news, IsInAB, To, false); + testValidityTable(news, IsInAB, ToOrCC, false); + testValidityTable(news, IsInAB, CCopy, false); + testValidityTable(news, IsInAB, Keywords, false); + testValidityTable(news, IsntInAB, Sender, false); + testValidityTable(news, IsntInAB, To, false); + testValidityTable(news, IsntInAB, ToOrCC, false); + testValidityTable(news, IsntInAB, CCopy, false); + testValidityTable(news, IsntInAB, Keywords, false); + testValidityTable(news, IsBefore, Sender, false); + testValidityTable(news, IsBefore, To, false); + testValidityTable(news, IsBefore, ToOrCC, false); + testValidityTable(news, IsBefore, CCopy, false); + testValidityTable(news, IsBefore, Keywords, false); + + // Get a message into the local filestore. function testAbSearch() continues the testing after the copy. + do_test_pending(); + copyListener.OnStopCopy(null); + return true; +} + +var copyListener = { + OnStartCopy() {}, + OnProgress(aProgress, aProgressMax) {}, + SetMessageKey(aKey) {}, + SetMessageId(aMessageId) {}, + OnStopCopy(aStatus) { + var fileName = Files.shift(); + if (fileName) { + var file = do_get_file(fileName); + MailServices.copy.copyFileMessage( + file, + localAccountUtils.inboxFolder, + null, + false, + 0, + "", + copyListener, + null + ); + } else { + testAbSearch(); + } + }, +}; + +// Runs at completion of copy + +// process each test from queue, calls itself upon completion of each search +function testAbSearch() { + print("Test AbSearch"); + var test = Tests.shift(); + if (test) { + new TestSearch( + localAccountUtils.inboxFolder, + test.value, + test.attrib, + test.op, + test.count, + testAbSearch + ); + } else { + do_test_finished(); + } +} diff --git a/comm/mailnews/search/test/unit/test_searchBody.js b/comm/mailnews/search/test/unit/test_searchBody.js new file mode 100644 index 0000000000..c2ec73c115 --- /dev/null +++ b/comm/mailnews/search/test/unit/test_searchBody.js @@ -0,0 +1,294 @@ +/* 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 various body search criteria. + */ +/* import-globals-from ../../../test/resources/searchTestUtils.js */ +load("../../../resources/searchTestUtils.js"); + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); + +var Isnt = Ci.nsMsgSearchOp.Isnt; +var Is = Ci.nsMsgSearchOp.Is; +var IsEmpty = Ci.nsMsgSearchOp.IsEmpty; +var IsntEmpty = Ci.nsMsgSearchOp.IsntEmpty; +var Contains = Ci.nsMsgSearchOp.Contains; +var DoesntContain = Ci.nsMsgSearchOp.DoesntContain; +var IsBefore = Ci.nsMsgSearchOp.IsBefore; // control entry not enabled + +var offlineMail = Ci.nsMsgSearchScope.offlineMail; +var onlineMail = Ci.nsMsgSearchScope.onlineMail; +var offlineMailFilter = Ci.nsMsgSearchScope.offlineMailFilter; +var news = Ci.nsMsgSearchScope.news; // control entry not enabled + +var Body = Ci.nsMsgSearchAttrib.Body; + +var Files = [ + "../../../data/base64-1", + "../../../data/basic1", + "../../../data/multipart-base64-2", + "../../../data/bug132340", + "../../../data/bad-charset.eml", + "../../../data/HTML-with-split-tag1.eml", + "../../../data/HTML-with-split-tag2.eml", + + // Base64 encoded bodies. + "../../../data/01-plaintext.eml", + "../../../data/02-plaintext+attachment.eml", + "../../../data/03-HTML.eml", + "../../../data/04-HTML+attachment.eml", + "../../../data/05-HTML+embedded-image.eml", + "../../../data/06-plaintext+HMTL.eml", + "../../../data/07-plaintext+(HTML+embedded-image).eml", + "../../../data/08-plaintext+HTML+attachment.eml", + "../../../data/09-(HTML+embedded-image)+attachment.eml", + "../../../data/10-plaintext+(HTML+embedded-image)+attachment.eml", + + // Bodies with non-ASCII characters in UTF-8 and other charsets. + "../../../data/11-plaintext.eml", + "../../../data/12-plaintext+attachment.eml", // using ISO-8859-7 (Greek) + "../../../data/13-HTML.eml", + "../../../data/14-HTML+attachment.eml", + "../../../data/15-HTML+embedded-image.eml", + "../../../data/16-plaintext+HMTL.eml", // text part is base64 encoded + "../../../data/17-plaintext+(HTML+embedded-image).eml", // HTML part is base64 encoded + "../../../data/18-plaintext+HTML+attachment.eml", + "../../../data/19-(HTML+embedded-image)+attachment.eml", + "../../../data/20-plaintext+(HTML+embedded-image)+attachment.eml", // using windows-1252 + + // Bodies with non-ASCII characters in UTF-8 and other charsets, all encoded with quoted printable. + "../../../data/21-plaintext.eml", + "../../../data/22-plaintext+attachment.eml", // using ISO-8859-7 (Greek) + "../../../data/23-HTML.eml", + "../../../data/24-HTML+attachment.eml", + "../../../data/25-HTML+embedded-image.eml", + "../../../data/26-plaintext+HMTL.eml", // text part is base64 encoded + "../../../data/27-plaintext+(HTML+embedded-image).eml", // HTML part is base64 encoded + "../../../data/28-plaintext+HTML+attachment.eml", + "../../../data/29-(HTML+embedded-image)+attachment.eml", + "../../../data/30-plaintext+(HTML+embedded-image)+attachment.eml", // using windows-1252 + + // Messages with message attachments, Content-Type: message/rfc822. + "../../../data/multipart-message-1.eml", // plaintext, has "bodyOfAttachedMessagePlain" + "../../../data/multipart-message-2.eml", // plaintext, base64, non-ASCII, has "bodyOfAttachedMessagePläin" + "../../../data/multipart-message-3.eml", // plaintext+HTML, non-ASCII in plaintext, has "bodyOfAttachedMessagePläin" + "../../../data/multipart-message-4.eml", // plaintext+HTML, non-ASCII in HTML, has "bodyOfAttachedMessägeHTML" + + // Message using ISO-2022-JP and CTE: quoted-printable. + "../../../data/iso-2022-jp-qp.eml", // plaintext, has 日本 (Japan), we shouldn't find =1B$BF|K. + + // Message using ISO-2022-JP and 7bit, but containing something that looks like quoted-printable. + // (bug 314637). + "../../../data/iso-2022-jp-not-qp.eml", // plaintext, has 現況 which contains =67. +]; +var Tests = [ + /* Translate Base64 messages */ + // "World!" is contained in three messages, but in bug132340 it's not in a text + // part and should not be found. + { value: "World!", op: Contains, count: 2 }, + /* Don't match the base64 text */ + { value: "DQp", op: Contains, count: 0 }, + /* Nested multipart/mixed, don't match */ + { value: "PGh", op: Contains, count: 0 }, + /* An encoded base-64 text/plain match */ + { value: "base 64 text", op: Contains, count: 1 }, + + // From the message with the bad charset. + { value: "Mätterhorn", op: Contains, count: 1 }, + { value: "Matterhörn", op: Contains, count: 1 }, + + // Comprehensive test of various MIME structures, messages 01 to 10. + // Messages 01 to 10 contain "huhu" once. + { value: "huhu", op: Contains, count: 10 }, + + // Messages 06, 07, 08, 10 contain "hihi" in the plaintext part. + { value: "hihi", op: Contains, count: 4 }, + + // The base64 of embedded images and attachments contains "iVBORw" and we don't + // want to find that. + { value: "iVBORw", op: Contains, count: 0 }, + + // The base64 of attachments contains "wMA005J0z" and we don't want to find that. + { value: "wMA005J0z", op: Contains, count: 0 }, + + // The base64 of the plaintext and HTML parts contains "U2VhcmNoIGZ" + // and we don't want to find that. + { value: "U2VhcmNoIGZ", op: Contains, count: 0 }, + + // Messages 11 and 13 to 20 contain "hühü" once. + { value: "hühü", op: Contains, count: 9 }, + // Message 12 contains Καλησπέρα (good evening in Greek). + { value: "Καλησπέρα", op: Contains, count: 1 }, + + // Messages 16, 17, 18, 20 contain "hïhï" in the plaintext part. + { value: "hïhï", op: Contains, count: 4 }, + + // Messages 21 and 23 to 30 contain "höhö" once. + { value: "höhö", op: Contains, count: 9 }, + // Message 22 contains Καλημέρα (good morning in Greek). + { value: "Καλημέρα", op: Contains, count: 1 }, + + // Messages 21, 23 and 24 contain "softbreak" broken by a soft line break. + { value: "softbreak", op: Contains, count: 3 }, + + // Messages 16, 17, 18, 20 contain "hähä" in the plaintext part. + { value: "hähä", op: Contains, count: 4 }, + + // The four messages with message/rfc822 attachment contain "bodyOfAttachedMessagePlain" + // or "bodyOfAttachedMessagePläin" in the plaintext part and "bodyOfAttachedMessageHTML" + // or "bodyOfAttachedMessägeHTML" in the HTML part. + { value: "bodyOfAttachedMessagePlain", op: Contains, count: 2 }, + { value: "bodyOfAttachedMessagePläin", op: Contains, count: 2 }, + { value: "bodyOfAttachedMessageHTML", op: Contains, count: 1 }, + { value: "bodyOfAttachedMessägeHTML", op: Contains, count: 1 }, + + // Test that we don't find anything in HTML tags. + { value: "ShouldNotFindThis", op: Contains, count: 0 }, + { value: "ShouldntFindThisEither", op: Contains, count: 0 }, + { value: "ShouldntFindHref", op: Contains, count: 0 }, + { value: "ShouldNotFindAcrossLines", op: Contains, count: 0 }, + { value: "ShouldFindThisAgain", op: Contains, count: 2 }, + { value: "ShouldFind AcrossLines", op: Contains, count: 2 }, + + // Test for ISO-2022-JP and CTE: quoted-printable, also 7bit looking like quoted-printable. + { value: "日本", op: Contains, count: 1 }, + { value: "=1B$BF|K", op: Contains, count: 0 }, + { value: "現況", op: Contains, count: 1 }, +]; + +function fixFile(file) { + var fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance( + Ci.nsIFileInputStream + ); + fstream.init(file, -1, -1, Ci.nsIFileInputStream.CLOSE_ON_EOF); + var sstream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance( + Ci.nsIScriptableInputStream + ); + sstream.init(fstream); + + var str = sstream.read(4096); + if (str.startsWith("From ")) { + sstream.close(); + fstream.close(); + return file; + } + var data = "From - Tue Oct 02 00:26:47 2007\r\n"; + do { + data += str; + str = sstream.read(4096); + } while (str.length > 0); + + sstream.close(); + fstream.close(); + + let targetFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); + targetFile.initWithFile(do_get_profile()); + targetFile.append(file.leafName); + let ostream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance( + Ci.nsIFileOutputStream + ); + ostream.init(targetFile, -1, -1, 0); + ostream.write(data, data.length); + ostream.close(); + return targetFile; +} + +var copyListener = { + OnStartCopy() {}, + OnProgress(aProgress, aProgressMax) {}, + SetMessageKey(aKey) {}, + SetMessageId(aMessageId) {}, + OnStopCopy(aStatus) { + var fileName = Files.shift(); + if (fileName) { + var file = fixFile(do_get_file(fileName)); + MailServices.copy.copyFileMessage( + file, + localAccountUtils.inboxFolder, + null, + false, + 0, + "", + copyListener, + null + ); + } else { + testBodySearch(); + } + }, +}; + +function run_test() { + localAccountUtils.loadLocalMailAccount(); + + // test that validity table terms are valid + + // offline mail table + testValidityTable(offlineMail, Contains, Body, true); + testValidityTable(offlineMail, DoesntContain, Body, true); + testValidityTable(offlineMail, Is, Body, true); + testValidityTable(offlineMail, Isnt, Body, true); + testValidityTable(offlineMail, IsEmpty, Body, false); + testValidityTable(offlineMail, IsntEmpty, Body, false); + testValidityTable(offlineMail, IsBefore, Body, false); + + // offline mail filter table + testValidityTable(offlineMailFilter, Contains, Body, true); + testValidityTable(offlineMailFilter, DoesntContain, Body, true); + testValidityTable(offlineMailFilter, Is, Body, true); + testValidityTable(offlineMailFilter, Isnt, Body, true); + testValidityTable(offlineMailFilter, IsEmpty, Body, false); + testValidityTable(offlineMailFilter, IsntEmpty, Body, false); + testValidityTable(offlineMailFilter, IsBefore, Body, false); + + // online mail + testValidityTable(onlineMail, Contains, Body, true); + testValidityTable(onlineMail, DoesntContain, Body, true); + testValidityTable(onlineMail, Is, Body, false); + testValidityTable(onlineMail, Isnt, Body, false); + testValidityTable(onlineMail, IsEmpty, Body, false); + testValidityTable(onlineMail, IsntEmpty, Body, false); + testValidityTable(onlineMail, IsBefore, Body, false); + + // online mail filter + /* testValidityTable(onlineMailFilter, Contains, Body, true); + testValidityTable(onlineMailFilter, DoesntContain, Body, true); + testValidityTable(onlineMailFilter, Is, Body, false); + testValidityTable(onlineMailFilter, Isnt, Body, false); + testValidityTable(onlineMailFilter, IsEmpty, Body, false); + testValidityTable(onlineMailFilter, IsntEmpty, Body, false); + testValidityTable(onlineMailFilter, IsBefore, Body, false);*/ + + // News does not support body tests + testValidityTable(news, Contains, Body, false); + testValidityTable(news, DoesntContain, Body, false); + testValidityTable(news, Is, Body, false); + testValidityTable(news, Isnt, Body, false); + testValidityTable(news, IsEmpty, Body, false); + testValidityTable(news, IsntEmpty, Body, false); + testValidityTable(news, IsBefore, Body, false); + + do_test_pending(); + copyListener.OnStopCopy(null); +} + +// process each test from queue, calls itself upon completion of each search +function testBodySearch() { + var test = Tests.shift(); + if (test) { + new TestSearch( + localAccountUtils.inboxFolder, + test.value, + Body, + test.op, + test.count, + testBodySearch + ); + } else { + do_test_finished(); + } +} diff --git a/comm/mailnews/search/test/unit/test_searchBoolean.js b/comm/mailnews/search/test/unit/test_searchBoolean.js new file mode 100644 index 0000000000..132acad4a3 --- /dev/null +++ b/comm/mailnews/search/test/unit/test_searchBoolean.js @@ -0,0 +1,239 @@ +/* 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/. */ + +/* + * Demonstrates and tests the use of grouped boolean expressions in search terms + */ + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); + +var gSearchSession = Cc[ + "@mozilla.org/messenger/searchSession;1" +].createInstance(Ci.nsIMsgSearchSession); + +var gHdr; // the message header for the one mailbox message + +var Tests = [ + { + A: false, + B: false, + C: false, + D: false, + matches: false, + }, + { + A: false, + B: false, + C: false, + D: true, + matches: false, + }, + { + A: false, + B: false, + C: true, + D: false, + matches: false, + }, + { + A: false, + B: false, + C: true, + D: true, + matches: false, + }, + { + A: false, + B: true, + C: false, + D: false, + matches: false, + }, + { + A: false, + B: true, + C: false, + D: true, + matches: true, + }, + { + A: false, + B: true, + C: true, + D: false, + matches: true, + }, + { + A: false, + B: true, + C: true, + D: true, + matches: true, + }, + { + A: true, + B: false, + C: false, + D: false, + matches: false, + }, + { + A: true, + B: false, + C: false, + D: true, + matches: true, + }, + { + A: true, + B: false, + C: true, + D: false, + matches: true, + }, + { + A: true, + B: false, + C: true, + D: true, + matches: true, + }, + { + A: true, + B: true, + C: false, + D: false, + matches: false, + }, + { + A: true, + B: true, + C: false, + D: true, + matches: true, + }, + { + A: true, + B: true, + C: true, + D: false, + matches: true, + }, + { + A: true, + B: true, + C: true, + D: true, + matches: true, + }, +]; + +var gHitCount = 0; +var searchListener = { + onSearchHit(dbHdr, folder) { + gHitCount++; + }, + onSearchDone(status) { + testSearch(); + }, + onNewSearch() { + gHitCount = 0; + }, +}; + +function run_test() { + localAccountUtils.loadLocalMailAccount(); + + /* + * I want to create and test a search term that uses this expression: + * (A || B ) && (C || D) + * + * The logical expressions A, B, C, and D will be represented by header + * string properties with values of T (true) or F (false). + * + */ + + // add a search term HdrProperty (some string) Is "T", with grouping + function addSearchTerm(aHdrProperty, aBeginGrouping, aEndGrouping, aBoolAnd) { + let searchTerm = gSearchSession.createTerm(); + searchTerm.attrib = Ci.nsMsgSearchAttrib.HdrProperty; + + let value = searchTerm.value; + // This is tricky - value.attrib must be set before actual values + value.attrib = Ci.nsMsgSearchAttrib.HdrProperty; + value.str = "T"; + searchTerm.value = value; + + searchTerm.op = Ci.nsMsgSearchOp.Is; + searchTerm.booleanAnd = aBoolAnd; + searchTerm.beginsGrouping = aBeginGrouping; + searchTerm.endsGrouping = aEndGrouping; + searchTerm.hdrProperty = aHdrProperty; + gSearchSession.appendTerm(searchTerm); + } + + gSearchSession.addScopeTerm( + Ci.nsMsgSearchScope.offlineMail, + localAccountUtils.inboxFolder + ); + gSearchSession.registerListener(searchListener); + // I tried using capital "A" but something makes it lower case internally, so it failed + addSearchTerm("a", true, false, true); // "(A" + addSearchTerm("b", false, true, false); // " || B)" + addSearchTerm("c", true, false, true); // " && (C" + addSearchTerm("d", false, true, false); // " || D)" + + var copyListener = { + OnStartCopy() {}, + OnProgress(aProgress, aProgressMax) {}, + SetMessageKey(aKey) { + gHdr = localAccountUtils.inboxFolder.GetMessageHeader(aKey); + }, + SetMessageId(aMessageId) {}, + OnStopCopy(aStatus) { + testSearch(); + }, + }; + + // Get a message into the local filestore. function testSearch() continues + // the testing after the copy. + var bugmail1 = do_get_file("../../../data/bugmail1"); + do_test_pending(); + MailServices.copy.copyFileMessage( + bugmail1, + localAccountUtils.inboxFolder, + null, + false, + 0, + "", + copyListener, + null + ); +} + +var gTest = null; +// process each test from queue, calls itself upon completion of each search +function testSearch() { + // tests the previous search + if (gTest) { + Assert.equal(gHitCount, gTest.matches ? 1 : 0); + } + gTest = Tests.shift(); + if (gTest) { + gHdr.setStringProperty("a", gTest.A ? "T" : "F"); + gHdr.setStringProperty("b", gTest.B ? "T" : "F"); + gHdr.setStringProperty("c", gTest.C ? "T" : "F"); + gHdr.setStringProperty("d", gTest.D ? "T" : "F"); + try { + gSearchSession.search(null); + } catch (e) { + dump(e); + } + } else { + gSearchSession.unregisterListener(searchListener); + do_test_finished(); + } +} diff --git a/comm/mailnews/search/test/unit/test_searchChaining.js b/comm/mailnews/search/test/unit/test_searchChaining.js new file mode 100644 index 0000000000..4bdbebab57 --- /dev/null +++ b/comm/mailnews/search/test/unit/test_searchChaining.js @@ -0,0 +1,90 @@ +/* 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/. */ + +// Test of chaining of search scopes in a search session. In particular, +// Bug 541969 made us not search an imap folder if the search scope before it +// there was an empty local folder. + +// main test + +/* import-globals-from ../../../test/resources/MessageGenerator.jsm */ +load("../../../resources/MessageGenerator.jsm"); + +var { IMAPPump, setupIMAPPump, teardownIMAPPump } = ChromeUtils.import( + "resource://testing-common/mailnews/IMAPpump.jsm" +); +var { ImapMessage } = ChromeUtils.import( + "resource://testing-common/mailnews/Imapd.jsm" +); +const { PromiseTestUtils } = ChromeUtils.import( + "resource://testing-common/mailnews/PromiseTestUtils.jsm" +); + +async function setupFolder() { + // add a single message to the imap inbox. + let messages = []; + let messageGenerator = new MessageGenerator(); + messages = messages.concat(messageGenerator.makeMessage()); + let synthMessage = messages[0]; + + let msgURI = Services.io.newURI( + "data:text/plain;base64," + btoa(synthMessage.toMessageString()) + ); + let message = new ImapMessage(msgURI.spec, IMAPPump.mailbox.uidnext++, []); + IMAPPump.mailbox.addMessage(message); + + // update folder to download header. + let listener = new PromiseTestUtils.PromiseUrlListener(); + IMAPPump.inbox.updateFolderWithListener(null, listener); + await listener.promise; +} + +async function searchTest() { + // Get the IMAP inbox... + var emptyLocal1 = + localAccountUtils.rootFolder.createLocalSubfolder("empty 1"); + + let searchSession = Cc[ + "@mozilla.org/messenger/searchSession;1" + ].createInstance(Ci.nsIMsgSearchSession); + + let searchTerm = searchSession.createTerm(); + searchTerm.matchAll = true; + searchSession.appendTerm(searchTerm); + searchSession.addScopeTerm(Ci.nsMsgSearchScope.offlineMail, emptyLocal1); + searchSession.addScopeTerm(Ci.nsMsgSearchScope.onlineMail, IMAPPump.inbox); + let listener = new PromiseTestUtils.PromiseSearchNotify( + searchSession, + searchListener + ); + searchSession.search(null); + await listener.promise; + + // After the search completes, there still seem to be active URLs, so we + // have to wait before we are done and clear. + await PromiseTestUtils.promiseDelay(1000); +} + +// nsIMsgSearchNotify implementation +var searchListener = { + numTotalMessages: 0, + QueryInterface: ChromeUtils.generateQI(["nsIMsgSearchNotify"]), + onNewSearch() { + this.numTotalMessages = 0; + }, + onSearchHit(dbHdr, folder) { + this.numTotalMessages++; + }, + onSearchDone(status) { + Assert.equal(this.numTotalMessages, 1); + return true; + }, +}; + +var tests = [setupIMAPPump, setupFolder, searchTest, teardownIMAPPump]; + +function run_test() { + tests.forEach(x => add_task(x)); + run_next_test(); +} diff --git a/comm/mailnews/search/test/unit/test_searchCustomTerm.js b/comm/mailnews/search/test/unit/test_searchCustomTerm.js new file mode 100644 index 0000000000..baea69767b --- /dev/null +++ b/comm/mailnews/search/test/unit/test_searchCustomTerm.js @@ -0,0 +1,112 @@ +/* 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/. */ + +/* + * Testing of custom search features. + * + */ +/* import-globals-from ../../../test/resources/searchTestUtils.js */ +load("../../../resources/searchTestUtils.js"); + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); + +var kCustomId = "xpcomtest@mozilla.org#test"; +var gHdr; + +var Tests = [ + { + setValue: "iamgood", + testValue: "iamnotgood", + op: Ci.nsMsgSearchOp.Is, + count: 0, + }, + { + setValue: "iamgood", + testValue: "iamgood", + op: Ci.nsMsgSearchOp.Is, + count: 1, + }, +]; + +// nsIMsgSearchCustomTerm object +var customTerm = { + id: kCustomId, + name: "term name", + getEnabled(scope, op) { + return ( + scope == Ci.nsMsgSearchScope.offlineMail && op == Ci.nsMsgSearchOp.Is + ); + }, + getAvailable(scope, op) { + return ( + scope == Ci.nsMsgSearchScope.offlineMail && op == Ci.nsMsgSearchOp.Is + ); + }, + getAvailableOperators(scope) { + return [Ci.nsMsgSearchOp.Is]; + }, + match(msgHdr, searchValue, searchOp) { + switch (searchOp) { + case Ci.nsMsgSearchOp.Is: + if (msgHdr.getStringProperty("theTestProperty") == searchValue) { + return true; + } + } + return false; + }, +}; + +function run_test() { + localAccountUtils.loadLocalMailAccount(); + MailServices.filters.addCustomTerm(customTerm); + + var copyListener = { + OnStartCopy() {}, + OnProgress(aProgress, aProgressMax) {}, + SetMessageKey(aKey) { + gHdr = localAccountUtils.inboxFolder.GetMessageHeader(aKey); + }, + SetMessageId(aMessageId) {}, + OnStopCopy(aStatus) { + doTest(); + }, + }; + + // Get a message into the local filestore. + // function testSearch() continues the testing after the copy. + let bugmail1 = do_get_file("../../../data/bugmail1"); + do_test_pending(); + + MailServices.copy.copyFileMessage( + bugmail1, + localAccountUtils.inboxFolder, + null, + false, + 0, + "", + copyListener, + null + ); +} + +function doTest() { + let test = Tests.shift(); + if (test) { + gHdr.setStringProperty("theTestProperty", test.setValue); + new TestSearch( + localAccountUtils.inboxFolder, + test.testValue, + Ci.nsMsgSearchAttrib.Custom, + test.op, + test.count, + doTest, + kCustomId + ); + } else { + gHdr = null; + do_test_finished(); + } +} diff --git a/comm/mailnews/search/test/unit/test_searchJunk.js b/comm/mailnews/search/test/unit/test_searchJunk.js new file mode 100644 index 0000000000..fdffd96165 --- /dev/null +++ b/comm/mailnews/search/test/unit/test_searchJunk.js @@ -0,0 +1,322 @@ +/* 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/. */ + +// Testing of search by junk percent and junk score origin + +/* import-globals-from ../../../test/resources/searchTestUtils.js */ +load("../../../resources/searchTestUtils.js"); + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); + +var IsGreaterThan = Ci.nsMsgSearchOp.IsGreaterThan; +var IsLessThan = Ci.nsMsgSearchOp.IsLessThan; +var Is = Ci.nsMsgSearchOp.Is; +var Isnt = Ci.nsMsgSearchOp.Isnt; +var IsEmpty = Ci.nsMsgSearchOp.IsEmpty; +var IsntEmpty = Ci.nsMsgSearchOp.IsntEmpty; + +var offlineMail = Ci.nsMsgSearchScope.offlineMail; + +var JunkScoreOrigin = Ci.nsMsgSearchAttrib.JunkScoreOrigin; +var JunkPercent = Ci.nsMsgSearchAttrib.JunkPercent; +var JunkStatus = Ci.nsMsgSearchAttrib.JunkStatus; + +var fileName = "../../../data/bugmail1"; + +/* + * The search for junkpercent is defined as the effective value, + * while the "junkpercent" database term is always the result + * from the bayes filter. This is optimized to make views that + * rely on junk percent search work with the best value for junk + * percent, while allowing junk percent from the bayes filter + * to be saved for analysis. + * + * This means that the search for "junk percent" only uses the + * database junkpercent value if junkscoreorigin is "plugin". + * Otherwise, it uses junkstatus (if set) or defaults to 0 + * (not junk) if the message is unclassified. + */ + +var Tests = [ + { + // test empty junk status + junkScore: false, + testValue: 90, + attrib: JunkStatus, + op: IsEmpty, + count: 1, + }, + { + junkScore: false, + testValue: 90, + attrib: JunkStatus, + op: IsntEmpty, + count: 0, + }, + { + junkScore: "0", + junkScoreOrigin: "plugin", + junkPercent: "10", + testValue: 90, + attrib: JunkStatus, + op: IsntEmpty, + count: 1, + }, + { + junkScore: "0", + junkScoreOrigin: "plugin", + junkPercent: "10", + testValue: 90, + attrib: JunkStatus, + op: IsEmpty, + count: 0, + }, + { + junkScore: "100", + junkScoreOrigin: "plugin", + junkPercent: "10", + testValue: 90, + attrib: JunkStatus, + op: IsntEmpty, + count: 1, + }, + { + junkScore: "100", + junkScoreOrigin: "plugin", + junkPercent: "10", + testValue: 90, + attrib: JunkStatus, + op: IsEmpty, + count: 0, + }, + { + // Use junkpercent from database + junkScore: "0", + junkScoreOrigin: "plugin", + junkPercent: "10", + testValue: 90, + attrib: JunkPercent, + op: IsGreaterThan, + count: 0, + }, + { + junkScore: "0", + junkScoreOrigin: "plugin", + junkPercent: "10", + testValue: 90, + attrib: JunkPercent, + op: IsLessThan, + count: 1, + }, + { + junkScore: "0", + junkScoreOrigin: "plugin", + junkPercent: "10", + testValue: 90, + attrib: JunkPercent, + op: Is, + count: 0, + }, + { + junkScore: "0", + junkScoreOrigin: "plugin", + junkPercent: "90", + testValue: 10, + attrib: JunkPercent, + op: IsGreaterThan, + count: 1, + }, + { + junkScore: "0", + junkScoreOrigin: "plugin", + junkPercent: "90", + testValue: 10, + attrib: JunkPercent, + op: IsLessThan, + count: 0, + }, + { + junkScore: "0", + junkScoreOrigin: "plugin", + junkPercent: "10", + testValue: 10, + attrib: JunkPercent, + op: Is, + count: 1, + }, + { + // values set by user, use junkscore not junkpercent + junkScore: "0", + junkScoreOrigin: "user", + junkPercent: "90", + testValue: 50, + attrib: JunkPercent, + op: IsGreaterThan, + count: 0, + }, + { + junkScore: "0", + junkScoreOrigin: "user", + junkPercent: "90", + testValue: 50, + attrib: JunkPercent, + op: IsLessThan, + count: 1, + }, + { + junkScore: "0", + junkScoreOrigin: "user", + junkPercent: "90", + testValue: 50, + attrib: JunkPercent, + op: Is, + count: 0, + }, + { + junkScore: "100", + junkScoreOrigin: "user", + junkPercent: "10", + testValue: 50, + attrib: JunkPercent, + op: IsGreaterThan, + count: 1, + }, + { + junkScore: "100", + junkScoreOrigin: "user", + junkPercent: "10", + testValue: 50, + attrib: JunkPercent, + op: IsLessThan, + count: 0, + }, + { + junkScore: "0", + junkScoreOrigin: "user", + junkPercent: "90", + testValue: 0, + attrib: JunkPercent, + op: Is, + count: 1, + }, + { + // default to 0 when nothing set + junkScore: "", + junkScoreOrigin: "", + junkPercent: "", + testValue: 0, + attrib: JunkPercent, + op: Is, + count: 1, + }, + { + // junkscoreorigin search tests + junkScore: "0", + junkScoreOrigin: "plugin", + junkPercent: "50", + testValue: "plugin", + attrib: JunkScoreOrigin, + op: Is, + count: 1, + }, + { + junkScore: "0", + junkScoreOrigin: "plugin", + junkPercent: "50", + testValue: "plugin", + attrib: JunkScoreOrigin, + op: Isnt, + count: 0, + }, + { + junkScore: "0", + junkScoreOrigin: "filter", + junkPercent: "50", + testValue: "plugin", + attrib: JunkScoreOrigin, + op: Is, + count: 0, + }, + { + junkScore: "0", + junkScoreOrigin: "filter", + junkPercent: "50", + testValue: "plugin", + attrib: JunkScoreOrigin, + op: Isnt, + count: 1, + }, +]; + +function run_test() { + localAccountUtils.loadLocalMailAccount(); + + // test that validity table terms are valid + + // offline mail table + testValidityTable(offlineMail, Is, JunkPercent, true); + testValidityTable(offlineMail, Isnt, JunkPercent, false); + testValidityTable(offlineMail, IsGreaterThan, JunkPercent, true); + testValidityTable(offlineMail, IsLessThan, JunkPercent, true); + + testValidityTable(offlineMail, Is, JunkScoreOrigin, true); + testValidityTable(offlineMail, Isnt, JunkScoreOrigin, true); + testValidityTable(offlineMail, IsGreaterThan, JunkScoreOrigin, false); + testValidityTable(offlineMail, IsLessThan, JunkScoreOrigin, false); + + // Get a message into the local filestore. function testJunkSearch() continues the testing after the copy. + do_test_pending(); + var file = do_get_file(fileName); + MailServices.copy.copyFileMessage( + file, + localAccountUtils.inboxFolder, + null, + false, + 0, + "", + copyListener, + null + ); + return true; +} + +var hdr; +var copyListener = { + OnStartCopy() {}, + OnProgress(aProgress, aProgressMax) {}, + SetMessageKey(aKey) { + hdr = localAccountUtils.inboxFolder.GetMessageHeader(aKey); + }, + SetMessageId(aMessageId) {}, + OnStopCopy(aStatus) { + testJunkSearch(); + }, +}; + +// Runs at completion of each copy +// process each test from queue, calls itself upon completion of each search +function testJunkSearch() { + var test = Tests.shift(); + if (test) { + if (test.junkScore) { + hdr.setStringProperty("junkpercent", test.junkPercent); + hdr.setStringProperty("junkscoreorigin", test.junkScoreOrigin); + hdr.setStringProperty("junkscore", test.junkScore); + } + + new TestSearch( + localAccountUtils.inboxFolder, + test.testValue, + test.attrib, + test.op, + test.count, + testJunkSearch + ); + } else { + hdr = null; + do_test_finished(); + } +} diff --git a/comm/mailnews/search/test/unit/test_searchLocalizationStrings.js b/comm/mailnews/search/test/unit/test_searchLocalizationStrings.js new file mode 100644 index 0000000000..9de9b7eb0e --- /dev/null +++ b/comm/mailnews/search/test/unit/test_searchLocalizationStrings.js @@ -0,0 +1,61 @@ +/* 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 that localization strings added in bug 484147 are defined in preferences + +var gValidityManager = Cc[ + "@mozilla.org/mail/search/validityManager;1" +].getService(Ci.nsIMsgSearchValidityManager); + +var gStringBundle = Services.strings.createBundle( + "chrome://messenger/locale/search-attributes.properties" +); + +// The following table of valid table scopes matches the allowable table +// scopes in nsMsgSearchValidityManager::GetTable +var kValidScopes = [ + Ci.nsMsgSearchScope.offlineMail, + Ci.nsMsgSearchScope.offlineMailFilter, + Ci.nsMsgSearchScope.onlineMail, + Ci.nsMsgSearchScope.onlineMailFilter, + Ci.nsMsgSearchScope.news, + Ci.nsMsgSearchScope.newsFilter, + Ci.nsMsgSearchScope.localNews, + Ci.nsMsgSearchScope.LDAP, + Ci.nsMsgSearchScope.LDAPAnd, + Ci.nsMsgSearchScope.LocalAB, + Ci.nsMsgSearchScope.LocalABAnd, +]; + +function run_test() { + for (var index = 0; index < kValidScopes.length; ++index) { + let scope = kValidScopes[index]; + let table = gValidityManager.getTable(scope); + let attributes = table.getAvailableAttributes(); + let attribute; + while ((attribute = attributes.pop()) && attribute) { + let property = gValidityManager.getAttributeProperty(attribute); + let valid = false; + let localizedString; + try { + localizedString = gStringBundle.GetStringFromName(property); + valid = true; + } catch (e) { + dump("\n" + e); + } + valid = valid && localizedString && localizedString.length > 0; + if (!valid) { + dump( + "\nNo valid property for scope = " + + scope + + " attribute = " + + attribute + + " property = " + + property + ); + } + Assert.ok(valid); + } + } +} diff --git a/comm/mailnews/search/test/unit/test_searchTag.js b/comm/mailnews/search/test/unit/test_searchTag.js new file mode 100644 index 0000000000..321c22a6cf --- /dev/null +++ b/comm/mailnews/search/test/unit/test_searchTag.js @@ -0,0 +1,490 @@ +/* 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/. */ + +/* + * Testing of tag search features. + * + * Specifically tests changes implemented in bug 217034 + * Does not do comprehensive testing. + * + */ +/* import-globals-from ../../../test/resources/searchTestUtils.js */ +load("../../../resources/searchTestUtils.js"); + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); + +var Isnt = Ci.nsMsgSearchOp.Isnt; +var Is = Ci.nsMsgSearchOp.Is; +var IsEmpty = Ci.nsMsgSearchOp.IsEmpty; +var IsntEmpty = Ci.nsMsgSearchOp.IsntEmpty; +var Contains = Ci.nsMsgSearchOp.Contains; +var DoesntContain = Ci.nsMsgSearchOp.DoesntContain; +var IsBefore = Ci.nsMsgSearchOp.IsBefore; // control entry not enabled + +var offlineMail = Ci.nsMsgSearchScope.offlineMail; +var onlineMail = Ci.nsMsgSearchScope.onlineMail; +var offlineMailFilter = Ci.nsMsgSearchScope.offlineMailFilter; +var onlineMailFilter = Ci.nsMsgSearchScope.onlineMailFilter; +var news = Ci.nsMsgSearchScope.news; // control entry not enabled + +var Keywords = Ci.nsMsgSearchAttrib.Keywords; + +// test tags +var Tag1 = "istag"; +var Tag2 = "notistag"; +var Tag3 = "istagnot"; +var Tag4 = "istagtoo"; +var Tag1Tag4 = Tag1 + " " + Tag4; +var Tag1Tag3 = Tag1 + " " + Tag3; +var Tag1Tag1 = Tag1 + " " + Tag1; + +var Tests = [ + // Message has a single valid tag + // test the valid tag + { + msgTag: Tag1, + testTag: Tag1, + op: Is, + count: 1, + }, + { + msgTag: Tag1, + testTag: Tag1, + op: Isnt, + count: 0, + }, + { + msgTag: Tag1, + testTag: Tag1, + op: Contains, + count: 1, + }, + { + msgTag: Tag1, + testTag: Tag1, + op: DoesntContain, + count: 0, + }, + { + msgTag: Tag1, + testTag: Tag1, + op: IsEmpty, + count: 0, + }, + { + msgTag: Tag1, + testTag: Tag1, + op: IsntEmpty, + count: 1, + }, + // test an invalid tag, should act like empty + { + msgTag: Tag2, + testTag: Tag1, + op: Contains, + count: 0, + }, + { + msgTag: Tag2, + testTag: Tag1, + op: DoesntContain, + count: 1, + }, + { + msgTag: Tag2, + testTag: Tag1, + op: Is, + count: 0, + }, + { + msgTag: Tag2, + testTag: Tag1, + op: Isnt, + count: 1, + }, + { + msgTag: Tag2, + testTag: Tag1, + op: IsEmpty, + count: 1, + }, + { + msgTag: Tag2, + testTag: Tag1, + op: IsntEmpty, + count: 0, + }, + // Message has two valid tags + // test first tag + { + msgTag: Tag1Tag4, + testTag: Tag1, + op: Is, + count: 0, + }, + { + msgTag: Tag1Tag4, + testTag: Tag1, + op: Isnt, + count: 1, + }, + { + msgTag: Tag1Tag4, + testTag: Tag1, + op: Contains, + count: 1, + }, + { + msgTag: Tag1Tag4, + testTag: Tag1, + op: DoesntContain, + count: 0, + }, + { + msgTag: Tag1Tag4, + testTag: Tag1, + op: IsEmpty, + count: 0, + }, + { + msgTag: Tag1Tag4, + testTag: Tag1, + op: IsntEmpty, + count: 1, + }, + // test second tag + { + msgTag: Tag1Tag4, + testTag: Tag4, + op: Is, + count: 0, + }, + { + msgTag: Tag1Tag4, + testTag: Tag4, + op: Isnt, + count: 1, + }, + { + msgTag: Tag1Tag4, + testTag: Tag4, + op: Contains, + count: 1, + }, + { + msgTag: Tag1Tag4, + testTag: Tag4, + op: DoesntContain, + count: 0, + }, + { + msgTag: Tag1Tag4, + testTag: Tag4, + op: IsEmpty, + count: 0, + }, + { + msgTag: Tag1Tag4, + testTag: Tag4, + op: IsntEmpty, + count: 1, + }, + // test tag not in message + { + msgTag: Tag1Tag4, + testTag: Tag2, + op: Is, + count: 0, + }, + { + msgTag: Tag1Tag4, + testTag: Tag2, + op: Isnt, + count: 1, + }, + { + msgTag: Tag1Tag4, + testTag: Tag2, + op: Contains, + count: 0, + }, + { + msgTag: Tag1Tag4, + testTag: Tag2, + op: DoesntContain, + count: 1, + }, + { + msgTag: Tag1Tag4, + testTag: Tag2, + op: IsEmpty, + count: 0, + }, + { + msgTag: Tag1Tag4, + testTag: Tag2, + op: IsntEmpty, + count: 1, + }, + // empty message + { + msgTag: "", + testTag: Tag2, + op: Is, + count: 0, + }, + { + msgTag: "", + testTag: Tag2, + op: Isnt, + count: 1, + }, + { + msgTag: "", + testTag: Tag2, + op: Contains, + count: 0, + }, + { + msgTag: "", + testTag: Tag2, + op: DoesntContain, + count: 1, + }, + { + msgTag: "", + testTag: Tag2, + op: IsEmpty, + count: 1, + }, + { + msgTag: "", + testTag: Tag2, + op: IsntEmpty, + count: 0, + }, + // message with two tags, only one is valid + // test with the single valid tag + { + msgTag: Tag1Tag3, + testTag: Tag1, + op: Is, + count: 1, + }, + { + msgTag: Tag1Tag3, + testTag: Tag1, + op: Isnt, + count: 0, + }, + { + msgTag: Tag1Tag3, + testTag: Tag1, + op: Contains, + count: 1, + }, + { + msgTag: Tag1Tag3, + testTag: Tag1, + op: DoesntContain, + count: 0, + }, + { + msgTag: Tag1Tag3, + testTag: Tag1, + op: IsEmpty, + count: 0, + }, + { + msgTag: Tag1Tag3, + testTag: Tag1, + op: IsntEmpty, + count: 1, + }, + // test with a tag not in the message + { + msgTag: Tag1Tag3, + testTag: Tag2, + op: Is, + count: 0, + }, + { + msgTag: Tag1Tag3, + testTag: Tag2, + op: Isnt, + count: 1, + }, + { + msgTag: Tag1Tag3, + testTag: Tag2, + op: Contains, + count: 0, + }, + { + msgTag: Tag1Tag3, + testTag: Tag2, + op: DoesntContain, + count: 1, + }, + { + msgTag: Tag1Tag3, + testTag: Tag2, + op: IsEmpty, + count: 0, + }, + { + msgTag: Tag1Tag3, + testTag: Tag2, + op: IsntEmpty, + count: 1, + }, + // Message has a duplicated tag + // test the tag + { + msgTag: Tag1Tag1, + testTag: Tag1, + op: Is, + count: 1, + }, + { + msgTag: Tag1Tag1, + testTag: Tag1, + op: Isnt, + count: 0, + }, + { + msgTag: Tag1Tag1, + testTag: Tag1, + op: Contains, + count: 1, + }, + { + msgTag: Tag1Tag1, + testTag: Tag1, + op: DoesntContain, + count: 0, + }, + { + msgTag: Tag1Tag1, + testTag: Tag1, + op: IsEmpty, + count: 0, + }, + { + msgTag: Tag1Tag1, + testTag: Tag1, + op: IsntEmpty, + count: 1, + }, +]; + +var hdr; + +function run_test() { + localAccountUtils.loadLocalMailAccount(); + + // test that validity table terms are valid + + // offline mail table + testValidityTable(offlineMail, Contains, Keywords, true); + testValidityTable(offlineMail, DoesntContain, Keywords, true); + testValidityTable(offlineMail, Is, Keywords, true); + testValidityTable(offlineMail, Isnt, Keywords, true); + testValidityTable(offlineMail, IsEmpty, Keywords, true); + testValidityTable(offlineMail, IsntEmpty, Keywords, true); + testValidityTable(offlineMail, IsBefore, Keywords, false); + + // offline mail filter table + testValidityTable(offlineMailFilter, Contains, Keywords, true); + testValidityTable(offlineMailFilter, DoesntContain, Keywords, true); + testValidityTable(offlineMailFilter, Is, Keywords, true); + testValidityTable(offlineMailFilter, Isnt, Keywords, true); + testValidityTable(offlineMailFilter, IsEmpty, Keywords, true); + testValidityTable(offlineMailFilter, IsntEmpty, Keywords, true); + testValidityTable(offlineMailFilter, IsBefore, Keywords, false); + + // online mail + testValidityTable(onlineMail, Contains, Keywords, true); + testValidityTable(onlineMail, DoesntContain, Keywords, true); + testValidityTable(onlineMail, Is, Keywords, false); + testValidityTable(onlineMail, Isnt, Keywords, false); + testValidityTable(onlineMail, IsEmpty, Keywords, false); + testValidityTable(onlineMail, IsntEmpty, Keywords, false); + testValidityTable(onlineMail, IsBefore, Keywords, false); + + // online mail filter + testValidityTable(onlineMailFilter, Contains, Keywords, true); + testValidityTable(onlineMailFilter, DoesntContain, Keywords, true); + testValidityTable(onlineMailFilter, Is, Keywords, true); + testValidityTable(onlineMailFilter, Isnt, Keywords, true); + testValidityTable(onlineMailFilter, IsEmpty, Keywords, true); + testValidityTable(onlineMailFilter, IsntEmpty, Keywords, true); + testValidityTable(onlineMailFilter, IsBefore, Keywords, false); + + // news + testValidityTable(news, Contains, Keywords, false); + testValidityTable(news, DoesntContain, Keywords, false); + testValidityTable(news, Is, Keywords, false); + testValidityTable(news, Isnt, Keywords, false); + testValidityTable(news, IsEmpty, Keywords, false); + testValidityTable(news, IsntEmpty, Keywords, false); + testValidityTable(news, IsBefore, Keywords, false); + + // delete any existing tags + let tagArray = MailServices.tags.getAllTags(); + for (var i = 0; i < tagArray.length; i++) { + MailServices.tags.deleteKey(tagArray[i].key); + } + + // add as valid tags Tag1 and Tag4 + MailServices.tags.addTagForKey(Tag1, Tag1, null, null); + MailServices.tags.addTagForKey(Tag4, Tag4, null, null); + + var copyListener = { + OnStartCopy() {}, + OnProgress(aProgress, aProgressMax) {}, + SetMessageKey(aKey) { + hdr = localAccountUtils.inboxFolder.GetMessageHeader(aKey); + }, + SetMessageId(aMessageId) {}, + OnStopCopy(aStatus) { + testKeywordSearch(); + }, + }; + + // Get a message into the local filestore. function testKeywordSearch() continues the testing after the copy. + var bugmail1 = do_get_file("../../../data/bugmail1"); + do_test_pending(); + MailServices.copy.copyFileMessage( + bugmail1, + localAccountUtils.inboxFolder, + null, + false, + 0, + "", + copyListener, + null + ); +} + +// process each test from queue, calls itself upon completion of each search +function testKeywordSearch() { + var test = Tests.shift(); + if (test) { + hdr.setStringProperty("keywords", test.msgTag); + new TestSearch( + localAccountUtils.inboxFolder, + test.testTag, + Ci.nsMsgSearchAttrib.Keywords, + test.op, + test.count, + testKeywordSearch + ); + } else { + hdr = null; + do_test_finished(); + } +} diff --git a/comm/mailnews/search/test/unit/test_searchUint32HdrProperty.js b/comm/mailnews/search/test/unit/test_searchUint32HdrProperty.js new file mode 100644 index 0000000000..e31f4db7d2 --- /dev/null +++ b/comm/mailnews/search/test/unit/test_searchUint32HdrProperty.js @@ -0,0 +1,141 @@ +/* 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/. */ + +/* + * Testing of Uint32HdrProperty search attribute. Adapted from test_search.js + */ + +/* import-globals-from ../../../test/resources/searchTestUtils.js */ +load("../../../resources/searchTestUtils.js"); + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); + +var Isnt = Ci.nsMsgSearchOp.Isnt; +var Is = Ci.nsMsgSearchOp.Is; +var IsGreaterThan = Ci.nsMsgSearchOp.IsGreaterThan; +var IsLessThan = Ci.nsMsgSearchOp.IsLessThan; + +var Tests = [ + // test a property that does not exist + { + hdrProperty: "idonotexist", + op: Is, + value: 1, + count: 0, + }, + { + hdrProperty: "idonotexist", + op: Isnt, + value: 1, + count: 1, + }, + // add a property and test its value + { + setup: function setupProperty() { + for (let msgHdr of localAccountUtils.inboxFolder.msgDatabase.enumerateMessages()) { + msgHdr.setUint32Property("iam23", 23); + } + }, + hdrProperty: "iam23", + op: Is, + value: 23, + count: 1, + }, + { + hdrProperty: "iam23", + op: Isnt, + value: 23, + count: 0, + }, + { + hdrProperty: "iam23", + op: Is, + value: 17, + count: 0, + }, + { + hdrProperty: "iam23", + op: Isnt, + value: 17, + count: 1, + }, + { + hdrProperty: "iam23", + op: IsGreaterThan, + value: 25, + count: 0, + }, + { + hdrProperty: "iam23", + op: IsLessThan, + value: 25, + count: 1, + }, + { + hdrProperty: "iam23", + op: IsGreaterThan, + value: 17, + count: 1, + }, + { + hdrProperty: "iam23", + op: IsLessThan, + value: 17, + count: 0, + }, +]; + +function run_test() { + localAccountUtils.loadLocalMailAccount(); + + var copyListener = { + OnStartCopy() {}, + OnProgress(aProgress, aProgressMax) {}, + SetMessageKey(aKey) {}, + SetMessageId(aMessageId) {}, + OnStopCopy(aStatus) { + testSearch(); + }, + }; + + // Get a message into the local filestore. function testSearch() continues + // the testing after the copy. + var bugmail1 = do_get_file("../../../data/bugmail1"); + do_test_pending(); + MailServices.copy.copyFileMessage( + bugmail1, + localAccountUtils.inboxFolder, + null, + false, + 0, + "", + copyListener, + null + ); +} + +// process each test from queue, calls itself upon completion of each search +function testSearch() { + var test = Tests.shift(); + if (test) { + if (test.setup) { + test.setup(); + } + new TestSearch( + localAccountUtils.inboxFolder, + test.value, + Ci.nsMsgSearchAttrib.Uint32HdrProperty, + test.op, + test.count, + testSearch, + null, + null, + test.hdrProperty + ); + } else { + do_test_finished(); + } +} diff --git a/comm/mailnews/search/test/unit/xpcshell.ini b/comm/mailnews/search/test/unit/xpcshell.ini new file mode 100644 index 0000000000..3157b90aea --- /dev/null +++ b/comm/mailnews/search/test/unit/xpcshell.ini @@ -0,0 +1,20 @@ +[DEFAULT] +head = head_mailbase.js +tail = + +[test_base64_decoding.js] +[test_bug366491.js] +[test_bug404489.js] +[test_copyThenMoveManual.js] +[test_junkWhitelisting.js] +[test_quarantineFilterMove.js] +[test_search.js] +[test_searchAddressInAb.js] +[test_searchBody.js] +[test_searchBoolean.js] +[test_searchChaining.js] +[test_searchCustomTerm.js] +[test_searchJunk.js] +[test_searchLocalizationStrings.js] +[test_searchTag.js] +[test_searchUint32HdrProperty.js] |