129 lines
4.8 KiB
C#
129 lines
4.8 KiB
C#
using Omika.App.Controls;
|
|
|
|
namespace Omika.Tests.Mobile.Local;
|
|
|
|
/// <summary>
|
|
/// Tests du parseur HTML de l'aperçu Email (<see cref="EmailHtmlParser"/>) :
|
|
/// 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.
|
|
/// </summary>
|
|
public class EmailHtmlParserTests
|
|
{
|
|
private static readonly byte[] Png = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
|
|
|
|
private static string Img(string mime, byte[] bytes) =>
|
|
$"<img src=\"data:{mime};base64,{Convert.ToBase64String(bytes)}\" />";
|
|
|
|
private static IReadOnlyList<HtmlInline> 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<HtmlInline> inlines = InlinesPremierBloc("<p>Bonjour</p>");
|
|
|
|
HtmlRun run = Assert.IsType<HtmlRun>(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("<table><tr><td>A</td><td>B</td></tr></table>"));
|
|
HtmlTable table = Assert.IsType<HtmlTable>(bloc);
|
|
|
|
HtmlRow row = Assert.Single(table.Rows);
|
|
Assert.Equal(2, row.Cells.Count);
|
|
Assert.Equal("A", Assert.IsType<HtmlRun>(Assert.Single(row.Cells[0].Inlines)).Text);
|
|
Assert.Equal("B", Assert.IsType<HtmlRun>(Assert.Single(row.Cells[1].Inlines)).Text);
|
|
}
|
|
|
|
// TEST 3 : img PNG data URI → image créée
|
|
[Fact]
|
|
public void Image_PngDataUri_Decodee()
|
|
{
|
|
IReadOnlyList<HtmlInline> inlines = InlinesPremierBloc($"<p>{Img("image/png", Png)}</p>");
|
|
|
|
HtmlImage image = Assert.IsType<HtmlImage>(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<HtmlInline> inlines = InlinesPremierBloc(
|
|
$"<p>{Img("image/png", Png)}{Img("image/jpeg", [0xFF, 0xD8, 0xFF, 0xE0])}</p>");
|
|
|
|
Assert.Equal(2, inlines.OfType<HtmlImage>().Count());
|
|
}
|
|
|
|
// TEST 5 : Base64 invalide → pas de crash, pas d'image
|
|
[Fact]
|
|
public void Image_Base64Invalide_SansCrash()
|
|
{
|
|
IReadOnlyList<HtmlInline> inlines = InlinesPremierBloc(
|
|
"<p><img src=\"data:image/png;base64,!!!pas-du-base64!!!\" /></p>");
|
|
|
|
Assert.DoesNotContain(inlines, i => i is HtmlImage);
|
|
}
|
|
|
|
// TEST 6 : texte + image + texte → ordre conservé
|
|
[Fact]
|
|
public void Texte_Image_Texte_OrdreConserve()
|
|
{
|
|
IReadOnlyList<HtmlInline> inlines = InlinesPremierBloc(
|
|
$"<p>Avant{Img("image/png", Png)}Après</p>");
|
|
|
|
Assert.Equal(3, inlines.Count);
|
|
Assert.Equal("Avant", Assert.IsType<HtmlRun>(inlines[0]).Text);
|
|
Assert.IsType<HtmlImage>(inlines[1]);
|
|
Assert.Equal("Après", Assert.IsType<HtmlRun>(inlines[2]).Text);
|
|
}
|
|
|
|
// TEST 7 : image dans une cellule de tableau → bonne cellule
|
|
[Fact]
|
|
public void Image_DansCelluleTableau()
|
|
{
|
|
HtmlTable table = Assert.IsType<HtmlTable>(Assert.Single(EmailHtmlParser.Parser(
|
|
$"<table><tr><td>{Img("image/png", Png)}</td><td>30/01/2026</td></tr></table>")));
|
|
|
|
Assert.Single(table.Rows);
|
|
Assert.Contains(table.Rows[0].Cells[0].Inlines, i => i is HtmlImage);
|
|
Assert.Equal("30/01/2026", Assert.IsType<HtmlRun>(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<HtmlInline> inlines = InlinesPremierBloc("<p>Bonjour & bienvenue <test></p>");
|
|
|
|
HtmlRun run = Assert.IsType<HtmlRun>(Assert.Single(inlines));
|
|
Assert.Equal("Bonjour & bienvenue <test>", run.Text);
|
|
Assert.DoesNotContain("&", run.Text);
|
|
Assert.DoesNotContain("<p>", run.Text);
|
|
}
|
|
|
|
// Gras / italique / souligné propagés
|
|
[Fact]
|
|
public void Formatage_GrasItalique_Souligne()
|
|
{
|
|
IReadOnlyList<HtmlInline> inlines = InlinesPremierBloc(
|
|
"<p><b>Gras</b> <i>Italique</i> <u>Souligné</u></p>");
|
|
|
|
Assert.Equal(5, inlines.Count);
|
|
Assert.True(Assert.IsType<HtmlRun>(inlines[0]).Bold);
|
|
Assert.True(Assert.IsType<HtmlRun>(inlines[2]).Italic);
|
|
Assert.True(Assert.IsType<HtmlRun>(inlines[4]).Underline);
|
|
}
|
|
}
|