using Omika.App.Controls; namespace Omika.Tests.Mobile.Local; /// /// Tests du parseur HTML de l'aperçu Email () : /// le sous-ensemble produit par DocxHtmlConverter (paragraphes, tableaux, images /// data URI auto-fermantes, gras/italique) est transformé en modèle structuré, /// sans jamais exposer de balises brutes. /// public class EmailHtmlParserTests { private static readonly byte[] Png = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]; private static string Img(string mime, byte[] bytes) => $""; private static IReadOnlyList InlinesPremierBloc(string html) => EmailHtmlParser.Parser(html)[0] switch { HtmlParagraph p => p.Inlines, _ => throw new InvalidOperationException("Premier bloc non paragraphe.") }; // TEST 1 : paragraphe → texte visible [Fact] public void Paragraphe_TexteVisible() { IReadOnlyList inlines = InlinesPremierBloc("

Bonjour

"); HtmlRun run = Assert.IsType(Assert.Single(inlines)); Assert.Equal("Bonjour", run.Text); } // TEST 2 : table → 1 ligne / 2 cellules [Fact] public void Tableau_UneLigne_DeuxCellules() { HtmlBlock bloc = Assert.Single(EmailHtmlParser.Parser("
AB
")); HtmlTable table = Assert.IsType(bloc); HtmlRow row = Assert.Single(table.Rows); Assert.Equal(2, row.Cells.Count); Assert.Equal("A", Assert.IsType(Assert.Single(row.Cells[0].Inlines)).Text); Assert.Equal("B", Assert.IsType(Assert.Single(row.Cells[1].Inlines)).Text); } // TEST 3 : img PNG data URI → image créée [Fact] public void Image_PngDataUri_Decodee() { IReadOnlyList inlines = InlinesPremierBloc($"

{Img("image/png", Png)}

"); HtmlImage image = Assert.IsType(Assert.Single(inlines)); Assert.Equal("image/png", image.MimeType); Assert.Equal(Convert.ToBase64String(Png), image.Base64Data); } // TEST 4 : 2 img → 2 images [Fact] public void DeuxImages_DeuxImages() { IReadOnlyList inlines = InlinesPremierBloc( $"

{Img("image/png", Png)}{Img("image/jpeg", [0xFF, 0xD8, 0xFF, 0xE0])}

"); Assert.Equal(2, inlines.OfType().Count()); } // TEST 5 : Base64 invalide → pas de crash, pas d'image [Fact] public void Image_Base64Invalide_SansCrash() { IReadOnlyList inlines = InlinesPremierBloc( "

"); Assert.DoesNotContain(inlines, i => i is HtmlImage); } // TEST 6 : texte + image + texte → ordre conservé [Fact] public void Texte_Image_Texte_OrdreConserve() { IReadOnlyList inlines = InlinesPremierBloc( $"

Avant{Img("image/png", Png)}Après

"); Assert.Equal(3, inlines.Count); Assert.Equal("Avant", Assert.IsType(inlines[0]).Text); Assert.IsType(inlines[1]); Assert.Equal("Après", Assert.IsType(inlines[2]).Text); } // TEST 7 : image dans une cellule de tableau → bonne cellule [Fact] public void Image_DansCelluleTableau() { HtmlTable table = Assert.IsType(Assert.Single(EmailHtmlParser.Parser( $"
{Img("image/png", Png)}30/01/2026
"))); Assert.Single(table.Rows); Assert.Contains(table.Rows[0].Cells[0].Inlines, i => i is HtmlImage); Assert.Equal("30/01/2026", Assert.IsType(Assert.Single(table.Rows[0].Cells[1].Inlines)).Text); } // TEST 8 : aucune balise HTML brute affichée (entités décodées) [Fact] public void AucuneBaliseHtmlBrute_EntitesDecodees() { IReadOnlyList inlines = InlinesPremierBloc("

Bonjour & bienvenue <test>

"); HtmlRun run = Assert.IsType(Assert.Single(inlines)); Assert.Equal("Bonjour & bienvenue ", run.Text); Assert.DoesNotContain("&", run.Text); Assert.DoesNotContain("

", run.Text); } // Gras / italique / souligné propagés [Fact] public void Formatage_GrasItalique_Souligne() { IReadOnlyList inlines = InlinesPremierBloc( "

Gras Italique Souligné

"); Assert.Equal(5, inlines.Count); Assert.True(Assert.IsType(inlines[0]).Bold); Assert.True(Assert.IsType(inlines[2]).Italic); Assert.True(Assert.IsType(inlines[4]).Underline); } }