using System.Text; using Omika.Core.Services; namespace Omika.Tests.Services; /// /// Tests de la préparation pure d'une tentative d'envoi : composition du corps /// (BASE BODY + signature), décodage de signature, fusion CC/CCI effectifs /// (règles §4, §8-§11). Aucun réseau ni persistance. /// public class EmailEnvoiPreparationTests { // TEST 4 / 5 : la signature n'est ajoutée qu'au corps d'envoi, jamais au corps de base. [Fact] public void ComposerCorpsEnvoi_SansSignature_RetourneCorpsDeBase() { Assert.Equal("BODY", EmailEnvoiPreparation.ComposerCorpsEnvoi("BODY", null)); Assert.Equal("BODY", EmailEnvoiPreparation.ComposerCorpsEnvoi("BODY", " ")); Assert.Equal("BODY", EmailEnvoiPreparation.ComposerCorpsEnvoi("BODY", string.Empty)); } [Fact] public void ComposerCorpsEnvoi_AvecSignature_AppendLaSignature() { Assert.Equal("BODY
sig
", EmailEnvoiPreparation.ComposerCorpsEnvoi("BODY", "
sig
")); } // TEST 6 : changer de configuration (A → B) n'accumule jamais les signatures. [Fact] public void ComposerCorpsEnvoi_ConfigurationsDifferentes_SignaturesIndependantes() { const string baseBody = "BODY"; Assert.Equal("BODY", EmailEnvoiPreparation.ComposerCorpsEnvoi(baseBody, "")); Assert.Equal("BODY", EmailEnvoiPreparation.ComposerCorpsEnvoi(baseBody, "")); Assert.Equal("BODY", baseBody); // le corps de base n'est jamais muté. } [Fact] public void DecoderSignature_Base64Html_ExtraitBody() { string html = "

Signature

"; string b64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(html)); Assert.Equal("

Signature

", EmailEnvoiPreparation.DecoderSignature(b64)); } [Fact] public void DecoderSignature_VideOuAbsente_RetourneNull() { Assert.Null(EmailEnvoiPreparation.DecoderSignature(null)); Assert.Null(EmailEnvoiPreparation.DecoderSignature(" ")); } // TEST 7 : tabCC_CopieEmail ajouté au CC SMTP (fusion). [Fact] public void FusionnerCc_UserEtConfig_Fusionne() { IReadOnlyList result = EmailEnvoiPreparation.FusionnerCc( "client1@example.test", ["archive@example.test", "supervision@example.test"]); Assert.Equal(["client1@example.test", "archive@example.test", "supervision@example.test"], result); } // TEST 8 : en cas d'échec, seul le CC utilisateur est conservé (aucun CC config). [Fact] public void FusionnerCc_UserSeul_SansConfig() { IReadOnlyList result = EmailEnvoiPreparation.FusionnerCc("client1@example.test", null); Assert.Equal(["client1@example.test"], result); } // TEST 11 : fusion + dédoublonnage insensible à la casse + vides retirés. [Fact] public void FusionnerCc_DedoublonneEtNettoie() { IReadOnlyList result = EmailEnvoiPreparation.FusionnerCc( "A@x.com; b@x.com; ;a@X.com", ["a@x.com", "", "C@x.com"]); Assert.Equal(["A@x.com", "b@x.com", "C@x.com"], result); } // TEST 9 : bEnCopieCachee=true → adresse expéditrice ajoutée au CCI. [Fact] public void FusionnerCci_EnCopieCachee_AjouteSender() { IReadOnlyList result = EmailEnvoiPreparation.FusionnerCci("user@x.com", true, "sender@x.com"); Assert.Equal(["user@x.com", "sender@x.com"], result); } // TEST 10 : bEnCopieCachee=false → aucun auto-CCI. [Fact] public void FusionnerCci_SansEnCopieCachee_NeAjoutePasSender() { IReadOnlyList result = EmailEnvoiPreparation.FusionnerCci("user@x.com", false, "sender@x.com"); Assert.Equal(["user@x.com"], result); } [Fact] public void FusionnerCci_DedoublonneSender() { IReadOnlyList result = EmailEnvoiPreparation.FusionnerCci("sender@x.com", true, "sender@x.com"); Assert.Equal(["sender@x.com"], result); } // ===================================================================== // ME_IDDocPJ — construction des PKID HFSQL (règles §2, §6) // ===================================================================== // TEST PJ ID 1 : aucune pièce jointe → chaîne vide (jamais "0"). [Fact] public void ConstruireIdDocPj_AucunePiece_RetourneChaineVide() { Assert.Equal(string.Empty, EmailEnvoiPreparation.ConstruireIdDocPj([])); Assert.Equal(string.Empty, EmailEnvoiPreparation.ConstruireIdDocPj(null!)); } // TEST PJ ID 2 : une seule PJ → son PKID, sans séparateur. [Fact] public void ConstruireIdDocPj_UnePiece_RetourneLePk() { Assert.Equal("281474976850215", EmailEnvoiPreparation.ConstruireIdDocPj([281474976850215L])); } // TEST PJ ID 3 : plusieurs PJ → séparées par « ; », ordre conservé. [Fact] public void ConstruireIdDocPj_TroisPieces_SeparateurPointVirgule() { string result = EmailEnvoiPreparation.ConstruireIdDocPj( [281474976850215L, 281474976850216L, 281474976850217L]); Assert.Equal("281474976850215;281474976850216;281474976850217", result); } // TEST PJ ID 4 : jamais de virgule. [Fact] public void ConstruireIdDocPj_NeContientPasDeVirgule() { string result = EmailEnvoiPreparation.ConstruireIdDocPj( [281474976850215L, 281474976850216L]); Assert.DoesNotContain(",", result); } // TEST PJ ID 5 : jamais de GUID (uniquement des chiffres et « ; »). [Fact] public void ConstruireIdDocPj_NeContientPasDeGuid() { string result = EmailEnvoiPreparation.ConstruireIdDocPj( [281474976850215L, 281474976850216L]); Assert.Matches("^[0-9;]+$", result); Assert.DoesNotContain("-", result); } // TEST PJ ID 6 : aucun séparateur final. [Fact] public void ConstruireIdDocPj_AucunSeparateurFinal() { string result = EmailEnvoiPreparation.ConstruireIdDocPj( [281474976850215L, 281474976850216L]); Assert.False(result.EndsWith(';')); } // Règles §6 : IDs <= 0 ignorés, doublons supprimés. [Fact] public void ConstruireIdDocPj_IgnoreIdsNonPositifs_EtDedoublonne() { string result = EmailEnvoiPreparation.ConstruireIdDocPj( [0L, -5L, 281474976850215L, 281474976850215L, 281474976850216L]); Assert.Equal("281474976850215;281474976850216", result); } // ===================================================================== // ME_PieceJointes — chemins complets serveur (règles §5) // ===================================================================== // TEST PATH 1 : un seul document → son chemin complet serveur. [Fact] public void ConstruireCheminsPj_UnChemin_RetourneLeChemin() { Assert.Equal(@"D:\Documents\Client\Inter\photo.jpg", EmailEnvoiPreparation.ConstruireCheminsPj([@"D:\Documents\Client\Inter\photo.jpg"])); } // TEST PATH 2 : deux documents → PATH1;PATH2. [Fact] public void ConstruireCheminsPj_DeuxChemins_SeparateurPointVirgule() { string result = EmailEnvoiPreparation.ConstruireCheminsPj( [@"D:\Documents\a.jpg", @"D:\Documents\b.pdf"]); Assert.Equal(@"D:\Documents\a.jpg;D:\Documents\b.pdf", result); } // TEST PATH 5 : cardinalité identique entre ME_IDDocPJ et ME_PieceJointes. [Fact] public void IdDocPj_EtChemins_ComptesIdentiques() { long[] pks = [101, 205, 312]; string[] chemins = [@"D:\a.jpg", @"D:\b.pdf", @"D:\c.txt"]; string ids = EmailEnvoiPreparation.ConstruireIdDocPj(pks); string paths = EmailEnvoiPreparation.ConstruireCheminsPj(chemins); Assert.Equal("101;205;312", ids); Assert.Equal(3, ids.Split(';').Length); Assert.Equal(3, paths.Split(';').Length); } // Règles §5 : vides retirés, doublons supprimés (insensible à la casse), // aucun séparateur final. [Fact] public void ConstruireCheminsPj_RetireVides_Dedoublonne_SansSeparateurFinal() { string result = EmailEnvoiPreparation.ConstruireCheminsPj( [@"D:\a.jpg", "", " ", @"d:\A.JPG", @"D:\b.pdf"]); Assert.Equal(@"D:\a.jpg;D:\b.pdf", result); Assert.False(result.EndsWith(';')); } // Aucune pièce jointe → chaîne vide (jamais null ni "0"). [Fact] public void ConstruireCheminsPj_AucunChemin_RetourneChaineVide() { Assert.Equal(string.Empty, EmailEnvoiPreparation.ConstruireCheminsPj([])); Assert.Equal(string.Empty, EmailEnvoiPreparation.ConstruireCheminsPj(null!)); } }