From 91d7cd2120de17c629f6f87096837184cbf859c5 Mon Sep 17 00:00:00 2001 From: Jeffrey Stedfast Date: Thu, 14 Sep 2023 14:10:44 -0400 Subject: [PATCH] Added more unit tests for IMAP's NOTIFY feature --- UnitTests/Net/Imap/ImapClientTests.cs | 127 ++++---------- UnitTests/Net/Imap/ImapEventGroupTests.cs | 203 ++++++++++++++++++++++ 2 files changed, 241 insertions(+), 89 deletions(-) create mode 100644 UnitTests/Net/Imap/ImapEventGroupTests.cs diff --git a/UnitTests/Net/Imap/ImapClientTests.cs b/UnitTests/Net/Imap/ImapClientTests.cs index 91959058fe..4de529e641 100644 --- a/UnitTests/Net/Imap/ImapClientTests.cs +++ b/UnitTests/Net/Imap/ImapClientTests.cs @@ -208,13 +208,8 @@ public void TestArgumentExceptions () Assert.ThrowsAsync (async () => await client.NotifyAsync (true, null)); Assert.Throws (() => client.Notify (true, Array.Empty ())); Assert.ThrowsAsync (async () => await client.NotifyAsync (true, Array.Empty ())); - Assert.Throws (() => new ImapEventGroup (null, new List ())); - Assert.Throws (() => new ImapEventGroup (ImapMailboxFilter.Selected, null)); - Assert.Throws (() => new ImapMailboxFilter.Subtree (null)); - Assert.Throws (() => new ImapMailboxFilter.Subtree (new List ())); + Assert.Throws (() => new ImapMailboxFilter.Subtree (client.Inbox, null)); - Assert.Throws (() => new ImapMailboxFilter.Mailboxes (null)); - Assert.Throws (() => new ImapMailboxFilter.Mailboxes (new List ())); Assert.Throws (() => new ImapMailboxFilter.Mailboxes (client.Inbox, null)); Assert.Throws (() => client.GetFolder ((string) null)); @@ -5504,9 +5499,7 @@ public void TestGMail () Assert.Throws (() => client.EnableQuickResync ()); Assert.Throws (() => client.Notify (true, new List { - new ImapEventGroup (ImapMailboxFilter.Inboxes, new List { - ImapEvent.FlagChange - }) + new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.FlagChange, new ImapEvent.MessageNew (), ImapEvent.MessageExpunge) })); Assert.Throws (() => client.DisableNotify ()); @@ -5669,9 +5662,7 @@ public async Task TestGMailAsync () Assert.ThrowsAsync (async () => await client.EnableQuickResyncAsync ()); Assert.ThrowsAsync (async () => await client.NotifyAsync (true, new List { - new ImapEventGroup (ImapMailboxFilter.Inboxes, new List { - ImapEvent.FlagChange - }) + new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.FlagChange, new ImapEvent.MessageNew (), ImapEvent.MessageExpunge) })); Assert.ThrowsAsync (async () => await client.DisableNotifyAsync ()); @@ -6316,7 +6307,9 @@ static List CreateNotifyCommands () new ImapReplayCommand ("A00000006 IDLE\r\n", "dovecot.notify-idle.txt"), new ImapReplayCommand ("A00000006", "DONE\r\n", "dovecot.notify-idle-done.txt"), new ImapReplayCommand ("A00000007 NOTIFY NONE\r\n", ImapReplayCommandResponse.OK), - new ImapReplayCommand ("A00000008 LOGOUT\r\n", "gmail.logout.txt") + new ImapReplayCommand ("A00000008 NOTIFY SET STATUS (SELECTED (MessageNew (UID FLAGS ENVELOPE BODYSTRUCTURE MODSEQ BODY.PEEK[HEADER.FIELDS (REFERENCES)]) MessageExpunge FlagChange)) (MAILBOXES INBOX (MessageNew MessageExpunge MailboxMetadataChange ServerMetadataChange))\r\n", "dovecot.notify.txt"), + new ImapReplayCommand ("A00000009 NOTIFY NONE\r\n", ImapReplayCommandResponse.OK), + new ImapReplayCommand ("A00000010 LOGOUT\r\n", "gmail.logout.txt") }; } @@ -6347,45 +6340,6 @@ public void TestNotify () folder.Open (FolderAccess.ReadOnly); - // Test some InvalidOperationExceptions - - // This fires due to non-message events for a Selected mailbox filter - Assert.Throws (() => client.Notify (true, new List { - new ImapEventGroup (ImapMailboxFilter.Selected, new List { - ImapEvent.MailboxName, - }) - })); - - // This fires due to having MessageNew, but not MessageExpunged - Assert.Throws (() => client.Notify (true, new List { - new ImapEventGroup (ImapMailboxFilter.Selected, new List { - new ImapEvent.MessageNew (items, new HashSet ()) - }) - })); - - // This fires due to having MessageNew, but not MessageExpunged - Assert.Throws (() => client.Notify (true, new List { - new ImapEventGroup (ImapMailboxFilter.Selected, new List { - new ImapEvent.MessageNew (items, new HashSet ()) - }) - })); - - // This fires due to having FlagsChanged but not MessageNew and MessageExpunged - Assert.Throws (() => client.Notify (true, new List { - new ImapEventGroup (ImapMailboxFilter.Selected, new List { - ImapEvent.AnnotationChange, ImapEvent.FlagChange - }) - })); - - // This fires due to MessageNew being aded to a non-Selected folder - Assert.Throws (() => client.Notify (true, new List { - new ImapEventGroup (ImapMailboxFilter.Personal, new List { - new ImapEvent.MessageNew (items, new HashSet ()) - }) - })); - - Assert.Throws (() => new ImapEvent.MessageNew (null)); - client.Notify (true, new List { new ImapEventGroup (ImapMailboxFilter.Personal, new List { ImapEvent.MailboxName, @@ -6518,6 +6472,22 @@ public void TestNotify () client.DisableNotify (); + client.Notify (true, new List { + new ImapEventGroup (ImapMailboxFilter.Selected, new List { + new ImapEvent.MessageNew (items | MessageSummaryItems.References), + ImapEvent.MessageExpunge, + ImapEvent.FlagChange + }), + new ImapEventGroup (new ImapMailboxFilter.Mailboxes (inbox), new List { + new ImapEvent.MessageNew (), + ImapEvent.MessageExpunge, + ImapEvent.MailboxMetadataChange, + ImapEvent.ServerMetadataChange + }), + }); + + client.DisableNotify (); + client.Disconnect (true); } } @@ -6549,43 +6519,6 @@ public async Task TestNotifyAsync () await folder.OpenAsync (FolderAccess.ReadOnly); - // Test some InvalidOperationExceptions - - // This fires due to non-message events for a Selected mailbox filter - Assert.ThrowsAsync (async () => await client.NotifyAsync (true, new List { - new ImapEventGroup (ImapMailboxFilter.Selected, new List { - ImapEvent.MailboxName, - }) - })); - - // This fires due to having MessageNew, but not MessageExpunged - Assert.ThrowsAsync (async () => await client.NotifyAsync (true, new List { - new ImapEventGroup (ImapMailboxFilter.Selected, new List { - new ImapEvent.MessageNew (items, new HashSet ()) - }) - })); - - // This fires due to having MessageNew, but not MessageExpunged - Assert.ThrowsAsync (async () => await client.NotifyAsync (true, new List { - new ImapEventGroup (ImapMailboxFilter.Selected, new List { - new ImapEvent.MessageNew (items, new HashSet ()) - }) - })); - - // This fires due to having FlagsChanged but not MessageNew and MessageExpunged - Assert.ThrowsAsync (async () => await client.NotifyAsync (true, new List { - new ImapEventGroup (ImapMailboxFilter.Selected, new List { - ImapEvent.AnnotationChange, ImapEvent.FlagChange - }) - })); - - // This fires due to MessageNew being aded to a non-Selected folder - Assert.ThrowsAsync (async () => await client.NotifyAsync (true, new List { - new ImapEventGroup (ImapMailboxFilter.Personal, new List { - new ImapEvent.MessageNew (items, new HashSet ()) - }) - })); - await client.NotifyAsync (true, new List { new ImapEventGroup (ImapMailboxFilter.Personal, new List { ImapEvent.MailboxName, @@ -6718,6 +6651,22 @@ public async Task TestNotifyAsync () await client.DisableNotifyAsync (); + await client.NotifyAsync (true, new List { + new ImapEventGroup (ImapMailboxFilter.Selected, new List { + new ImapEvent.MessageNew (items | MessageSummaryItems.References), + ImapEvent.MessageExpunge, + ImapEvent.FlagChange + }), + new ImapEventGroup (new ImapMailboxFilter.Mailboxes (inbox), new List { + new ImapEvent.MessageNew (), + ImapEvent.MessageExpunge, + ImapEvent.MailboxMetadataChange, + ImapEvent.ServerMetadataChange + }), + }); + + await client.DisableNotifyAsync (); + await client.DisconnectAsync (true); } } diff --git a/UnitTests/Net/Imap/ImapEventGroupTests.cs b/UnitTests/Net/Imap/ImapEventGroupTests.cs new file mode 100644 index 0000000000..5c0f7e62ba --- /dev/null +++ b/UnitTests/Net/Imap/ImapEventGroupTests.cs @@ -0,0 +1,203 @@ +// +// ImapEventGroupTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2023 .NET Foundation and Contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System.Text; + +using MailKit; +using MailKit.Net.Imap; + +using MimeKit; + +namespace UnitTests.Net.Imap { + [TestFixture] + public class ImapEventGroupTests + { + [Test] + public void TestArgumentExceptions () + { + Assert.Throws (() => new ImapEventGroup (null, new List ())); + Assert.Throws (() => new ImapEventGroup (ImapMailboxFilter.Selected, (IList) null)); + + Assert.Throws (() => new ImapEventGroup (null)); + Assert.Throws (() => new ImapEventGroup (ImapMailboxFilter.Selected, null)); + + Assert.Throws (() => new ImapMailboxFilter.Mailboxes (null)); + Assert.Throws (() => new ImapMailboxFilter.Mailboxes (Array.Empty ())); + + Assert.Throws (() => new ImapMailboxFilter.Subtree (null)); + Assert.Throws (() => new ImapMailboxFilter.Subtree (Array.Empty ())); + + Assert.Throws (() => new ImapEvent.MessageNew (null)); + } + + static void AssertFormatEventGroup (ImapEventGroup eventGroup, string expected, bool expectedNotify) + { + using var engine = new ImapEngine (null); + bool notifySelectedNewExpunge = false; + var command = new StringBuilder (); + var args = new List (); + + if (expected == null) { + Assert.Throws (() => eventGroup.Format (engine, command, args, ref notifySelectedNewExpunge)); + } else { + eventGroup.Format (engine, command, args, ref notifySelectedNewExpunge); + + Assert.AreEqual (expected, command.ToString ()); + Assert.AreEqual (expectedNotify, notifySelectedNewExpunge, "notifySelectedNewExpunge"); + } + } + + [Test] + public void TestFormatEventGroup_None () + { + var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, Array.Empty ()); + + AssertFormatEventGroup (eventGroup, "(INBOXES NONE)", false); + } + + [Test] + public void TestFormatEventGroup_AnnotationChange_Requires_MessageNew_And_MessageExpunge () + { + var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.AnnotationChange); + + AssertFormatEventGroup (eventGroup, null, false); + } + + [Test] + public void TestFormatEventGroup_AnnotationChange_MessageNew_Requires_MessageExpunge () + { + var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.AnnotationChange, new ImapEvent.MessageNew (MessageSummaryItems.None)); + + AssertFormatEventGroup (eventGroup, null, false); + } + + [Test] + public void TestFormatEventGroup_AnnotationChange_MessageExpunge_Requires_MessageNew () + { + var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.AnnotationChange, ImapEvent.MessageExpunge); + + AssertFormatEventGroup (eventGroup, null, false); + } + + [Test] + public void TestFormatEventGroup_FlagChange_Requires_MessageNew_And_MessageExpunge () + { + var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.FlagChange); + + AssertFormatEventGroup (eventGroup, null, false); + } + + [Test] + public void TestFormatEventGroup_FlagChange_MessageNew_Requires_MessageExpunge () + { + var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.FlagChange, new ImapEvent.MessageNew (MessageSummaryItems.None)); + + AssertFormatEventGroup (eventGroup, null, false); + } + + [Test] + public void TestFormatEventGroup_FlagChange_MessageExpunge_Requires_MessageNew () + { + var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.FlagChange, ImapEvent.MessageExpunge); + + AssertFormatEventGroup (eventGroup, null, false); + } + + [Test] + public void TestFormatEventGroup_FlagChange_MessageNew_MessageExpunge_AnnotationChange () + { + var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.FlagChange, new ImapEvent.MessageNew (MessageSummaryItems.None), ImapEvent.MessageExpunge, ImapEvent.AnnotationChange); + + AssertFormatEventGroup (eventGroup, "(INBOXES (FlagChange MessageNew MessageExpunge AnnotationChange))", false); + } + + [Test] + public void TestFormatEventGroup_MessageExpunge_Requires_MessageNew () + { + var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.MessageExpunge); + + AssertFormatEventGroup (eventGroup, null, false); + } + + [Test] + public void TestFormatEventGroup_MessageNew_Requires_MessageExpunge () + { + var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, new ImapEvent.MessageNew (MessageSummaryItems.None)); + + AssertFormatEventGroup (eventGroup, null, false); + } + + [Test] + public void TestFormatEventGroup_MessageNew_MessageExpunge () + { + var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, new ImapEvent.MessageNew (MessageSummaryItems.None), ImapEvent.MessageExpunge); + + AssertFormatEventGroup (eventGroup, "(INBOXES (MessageNew MessageExpunge))", false); + } + + [Test] + public void TestFormatEventGroup_MessageNew_Headers_Requires_Selected () + { + var headers = new HashSet (new HeaderId[] { HeaderId.From, HeaderId.Subject, HeaderId.Date }); + var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, new ImapEvent.MessageNew (MessageSummaryItems.None, headers), ImapEvent.MessageExpunge); + + AssertFormatEventGroup (eventGroup, null, false); + } + + [Test] + public void TestFormatEventGroup_MessageNew_Items_Requires_Selected () + { + var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, new ImapEvent.MessageNew (MessageSummaryItems.Full), ImapEvent.MessageExpunge); + + AssertFormatEventGroup (eventGroup, null, false); + } + + [Test] + public void TestFormatEventGroup_MessageNew_WithSpecificHeaderIds () + { + var headers = new HashSet (new HeaderId[] { HeaderId.From, HeaderId.Subject, HeaderId.Date }); + var eventGroup = new ImapEventGroup (ImapMailboxFilter.Selected, new ImapEvent.MessageNew (MessageSummaryItems.None, headers), ImapEvent.MessageExpunge); + + AssertFormatEventGroup (eventGroup, "(SELECTED (MessageNew (BODY.PEEK[HEADER.FIELDS (FROM SUBJECT DATE)]) MessageExpunge))", true); + } + + [Test] + public void TestFormatEventGroup_Selected_Requires_OnlyMessageEvents () + { + var eventGroup = new ImapEventGroup (ImapMailboxFilter.Selected, ImapEvent.ServerMetadataChange); + + AssertFormatEventGroup (eventGroup, null, false); + } + + [Test] + public void TestFormatEventGroup_SelectedDelayed_Requires_OnlyMessageEvents () + { + var eventGroup = new ImapEventGroup (ImapMailboxFilter.SelectedDelayed, ImapEvent.ServerMetadataChange); + + AssertFormatEventGroup (eventGroup, null, false); + } + } +}