using MimeKit; namespace MaksIT.PostClient.Tests.Envelope; public class EnvelopeClassifierTests { [Fact] public void TransportHeader_IsItalianPec() { var info = EnvelopeClassifier.Classify( [new KeyValuePair("X-Trasporto", "posta-certificata")], ["daticert.xml", "postacert.eml"]); Assert.Equal(EnvelopeKind.PecTransport, info.Kind); Assert.Equal(EnvelopeRegion.Italy, info.Region); Assert.Equal("PEC", info.Badge); Assert.True(info.HasInnerMessage); } [Fact] public void RicevutaHeader_IsItalianReceipt() { var info = EnvelopeClassifier.Classify( [new KeyValuePair("X-Ricevuta", "accettazione")], ["daticert.xml"]); Assert.Equal(EnvelopeKind.PecReceipt, info.Kind); Assert.Equal(EnvelopeRegion.Italy, info.Region); Assert.Equal("RIC", info.Badge); Assert.False(info.HasInnerMessage); Assert.Equal(ReceiptStatus.Accepted, info.EventStatus); } [Fact] public void RiferimentoHeader_IsOriginalMessageId() { var info = EnvelopeClassifier.Classify( [ new KeyValuePair("X-Ricevuta", "avvenuta-consegna"), new KeyValuePair("X-Riferimento-Message-ID", "") ], ["daticert.xml"]); Assert.Equal(EnvelopeKind.PecReceipt, info.Kind); Assert.Equal("", info.Msgid); Assert.Equal(ReceiptStatus.Delivered, info.EventStatus); } [Fact] public void EtsiXml_IsEuropeanRem() { var info = EnvelopeClassifier.Classify( [], ["evidence.xml"], ""); Assert.Equal(EnvelopeKind.EidasRem, info.Kind); Assert.Equal(EnvelopeRegion.Europe, info.Region); Assert.Equal("REM", info.Badge); } [Fact] public void Ordinary_HasNoBadge() { var info = EnvelopeClassifier.Classify([], ["invoice.pdf"]); Assert.Equal(EnvelopeKind.Ordinary, info.Kind); Assert.Equal("", info.Badge); } [Fact] public void Label_ExplainsKind() { Assert.Equal("Certified mail (PEC)", EnvelopeKind.Label(EnvelopeKind.PecTransport)); Assert.Equal("PEC receipt", EnvelopeKind.Label(EnvelopeKind.PecReceipt)); Assert.Equal("Certified mail (REM)", EnvelopeKind.Label(EnvelopeKind.EidasRem)); Assert.Equal("Digitally signed", EnvelopeKind.Label(EnvelopeKind.SmimeSigned)); Assert.Equal("Ordinary mail", EnvelopeKind.Label(EnvelopeKind.Ordinary)); } } public class DaticertParserTests { [Fact] public void Parse_ReadsTipoGestoreId() { var xml = """ a@pec.example.it Fattura Example PEC id-1 <orig@studio.it> """; var data = DaticertParser.Parse(xml); Assert.NotNull(data); Assert.Equal("posta-certificata", data.Tipo); Assert.Equal("Example PEC", data.Gestore); Assert.Equal("id-1", data.Identificativo); Assert.Equal("a@pec.example.it", data.Mittente); Assert.Equal("", data.Msgid); } } public class EnvelopeUnwrapperTests { [Fact] public void Inspect_UnwrapsPostacert() { var xml = """ Example PEC id-1 """; var inner = new MimeMessage(); inner.From.Add(new MailboxAddress("Studio", "studio@example.it")); inner.Subject = "Inner letter"; inner.Body = new TextPart("plain") { Text = "hello inner" }; var mixed = new Multipart("mixed"); mixed.Add(new TextPart("plain") { Text = "wrapper text from gestore" }); mixed.Add(XmlPart("daticert.xml", xml)); mixed.Add(Rfc822Part(inner, "postacert.eml")); var outer = new MimeMessage(); outer.Headers.Add("X-Trasporto", "posta-certificata"); outer.Subject = "POSTA CERTIFICATA: Inner letter"; outer.From.Add(new MailboxAddress("", "posta-certificata@pec.example.it")); outer.Body = mixed; var parsed = EnvelopeUnwrapper.Inspect(outer); Assert.Equal(EnvelopeKind.PecTransport, parsed.Info.Kind); Assert.Equal(EnvelopeRegion.Italy, parsed.Info.Region); Assert.Equal("Example PEC", parsed.Info.Gestore); Assert.True(parsed.Info.HasInnerMessage); Assert.Equal("Inner letter", parsed.Inner?.Subject); Assert.Equal("hello inner", parsed.Inner?.TextBody); } [Fact] public void Inspect_ReceiptWithoutInner() { var xml = """ Example PEC id-2 """; var mixed = new Multipart("mixed"); mixed.Add(new TextPart("plain") { Text = "accettazione" }); mixed.Add(XmlPart("daticert.xml", xml)); var outer = new MimeMessage(); outer.Headers.Add("X-Ricevuta", "accettazione"); outer.Body = mixed; var parsed = EnvelopeUnwrapper.Inspect(outer); Assert.Equal(EnvelopeKind.PecReceipt, parsed.Info.Kind); Assert.False(parsed.Info.HasInnerMessage); Assert.Null(parsed.Inner); } [Fact] public void Inspect_SavedPostclientObjects_IfPresent() { var dir = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MaksIT", "Postclient", "objects"); if (!Directory.Exists(dir)) { dir = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Postclient", "objects"); } if (!Directory.Exists(dir)) return; var files = Directory.GetFiles(dir, "*.eml"); if (files.Length == 0) return; foreach (var file in files) { MimeMessage mime; try { mime = MimeMessage.Load(file, TestContext.Current.CancellationToken); } catch (IOException) { continue; } var parsed = EnvelopeUnwrapper.Inspect(mime); if (parsed.Info.Kind == EnvelopeKind.Ordinary) continue; if (parsed.Info.Kind is EnvelopeKind.PecTransport or EnvelopeKind.PecReceipt) Assert.Equal(EnvelopeRegion.Italy, parsed.Info.Region); if (parsed.Info.Kind == EnvelopeKind.EidasRem) Assert.Equal(EnvelopeRegion.Europe, parsed.Info.Region); } } private static MimePart XmlPart(string name, string xml) { var part = new MimePart("application", "xml") { Content = new MimeContent(new MemoryStream(System.Text.Encoding.UTF8.GetBytes(xml))), FileName = name }; part.ContentDisposition = new ContentDisposition(ContentDisposition.Attachment) { FileName = name }; part.ContentType.Name = name; return part; } private static MessagePart Rfc822Part(MimeMessage inner, string name) { var part = new MessagePart { Message = inner }; part.ContentDisposition = new ContentDisposition(ContentDisposition.Attachment) { FileName = name }; part.ContentType.Name = name; return part; } } public class ReceiptStatusTests { [Fact] public void FromTipo_PecDeliveryIsNotRead() { Assert.Equal(ReceiptStatus.Accepted, ReceiptStatus.FromTipo("accettazione")); Assert.Equal(ReceiptStatus.Delivered, ReceiptStatus.FromTipo("avvenuta-consegna")); Assert.Equal(ReceiptStatus.Failed, ReceiptStatus.FromTipo("mancata-consegna")); Assert.Equal( "Delivered to the recipient certified mailbox (not a read receipt).", ReceiptStatus.Explain("avvenuta-consegna")); } [Fact] public void FromTipo_RemRetrievalIsReadLike() { Assert.Equal(ReceiptStatus.Accepted, ReceiptStatus.FromTipo("SubmissionAcceptance")); Assert.Equal(ReceiptStatus.Delivered, ReceiptStatus.FromTipo("Delivery")); Assert.Equal(ReceiptStatus.Retrieved, ReceiptStatus.FromTipo("ContentConsignment")); Assert.Equal(ReceiptStatus.Retrieved, ReceiptStatus.FromTipo("Abholbestätigung")); Assert.Equal(ReceiptStatus.Delivered, ReceiptStatus.FromTipo("avis-de-reception")); } [Fact] public void Combine_DoesNotDowngradeDeliveredToAccepted() { var status = ReceiptStatus.Combine(ReceiptStatus.Submitted, ReceiptStatus.Accepted); status = ReceiptStatus.Combine(status, ReceiptStatus.Delivered); Assert.Equal(ReceiptStatus.Delivered, ReceiptStatus.Combine(status, ReceiptStatus.Accepted)); } } public class RemEvidenceParserTests { [Fact] public void Parse_ReadsEventAndRelatedId() { var xml = """ ContentConsignment orig@studio.it ev-1 """; var data = RemEvidenceParser.Parse(xml); Assert.NotNull(data); Assert.Equal("ContentConsignment", data.Event); Assert.Equal("orig@studio.it", data.RelatedMessageId); Assert.Equal("ev-1", data.EvidenceId); } } public class SentReceiptStoreTests { [Fact] public void RememberAndApply_MatchesMsgidAndSubject() { var path = Path.Combine(Path.GetTempPath(), "postclient-receipts-" + Guid.NewGuid().ToString("N") + ".json"); try { var store = new FileSentReceiptStore(path); store.Remember(new SentDispatch { MailboxId = "box-1", MessageId = "", Subject = "Fattura studio", Status = ReceiptStatus.Submitted }); Assert.Equal(ReceiptStatus.Submitted, store.StatusFor("box-1", "orig@studio.it")); store.ApplyEvidence("box-1", "", "id-9", "ACCETTAZIONE: Fattura studio", "accettazione"); Assert.Equal(ReceiptStatus.Accepted, store.StatusFor("box-1", "orig@studio.it")); store.ApplyEvidence("box-1", "orig@studio.it", null, "CONSEGNA: Fattura studio", "avvenuta-consegna"); Assert.Equal(ReceiptStatus.Delivered, store.StatusFor("box-1", "", "Fattura studio")); store.ApplyEvidence("box-1", null, null, "ACCETTAZIONE: Fattura studio", "accettazione"); Assert.Equal(ReceiptStatus.Delivered, store.StatusFor("box-1", "orig@studio.it")); } finally { if (File.Exists(path)) File.Delete(path); } } [Fact] public void ForgetMailbox_DropsOnlyThatAccount() { var path = Path.Combine(Path.GetTempPath(), "postclient-receipts-" + Guid.NewGuid().ToString("N") + ".json"); try { var store = new FileSentReceiptStore(path); store.Remember(new SentDispatch { MailboxId = "gmail-1", MessageId = "gmail@msg", Subject = "Hello from gmail", Status = ReceiptStatus.Submitted }); store.Remember(new SentDispatch { MailboxId = "pec-1", MessageId = "pec@msg", Subject = "Certified", Status = ReceiptStatus.Submitted }); store.ForgetMailbox("gmail-1"); Assert.Equal("", store.StatusFor("gmail-1", "gmail@msg", "Hello from gmail")); Assert.Equal(ReceiptStatus.Submitted, store.StatusFor("pec-1", "pec@msg")); } finally { if (File.Exists(path)) File.Delete(path); } } } public class MimeBodyTests { [Fact] public async Task FromMimeAsync_LeavesMessageUnread() { var mime = new MimeMessage(); mime.From.Add(new MailboxAddress("A", "a@b.c")); mime.To.Add(new MailboxAddress("B", "b@c.d")); mime.Subject = "Hello"; mime.Body = new TextPart("plain") { Text = "Hi" }; var body = await MimeBody.FromMimeAsync("INBOX", 8, mime, CancellationToken.None); Assert.False(body.Header.IsSeen); Assert.False(body.Header.IsFlagged); } [Fact] public async Task FromMimeAsync_NamedInlinePartCountsAsAttachment() { var mime = new MimeMessage(); mime.From.Add(new MailboxAddress("A", "a@b.c")); mime.To.Add(new MailboxAddress("B", "b@c.d")); mime.Subject = "Invoice"; var pdf = new MimePart("application", "pdf") { Content = new MimeContent(new MemoryStream("pdf"u8.ToArray())), ContentDisposition = new ContentDisposition(ContentDisposition.Inline), FileName = "invoice.pdf" }; mime.Body = new Multipart("mixed") { new TextPart("plain") { Text = "See attached." }, pdf }; var body = await MimeBody.FromMimeAsync("INBOX", 9, mime, CancellationToken.None); Assert.True(body.Header.HasAttachments); Assert.Contains(body.AttachmentFiles, f => f.Name == "invoice.pdf"); } [Fact] public async Task FromMimeAsync_CidImageInHtmlIsNotAttachment() { var mime = new MimeMessage(); mime.From.Add(new MailboxAddress("A", "a@b.c")); mime.To.Add(new MailboxAddress("B", "b@c.d")); mime.Subject = "Logo"; var image = new MimePart("image", "png") { Content = new MimeContent(new MemoryStream([0x89, 0x50])), ContentId = "logo@mail", ContentDisposition = new ContentDisposition(ContentDisposition.Inline) }; mime.Body = new Multipart("related") { new TextPart("html") { Text = "" }, image }; var body = await MimeBody.FromMimeAsync("INBOX", 10, mime, CancellationToken.None); Assert.False(body.Header.HasAttachments); } }