Files
agent-wiki-ui/tests/agent-wiki-ui.Tests/Gui/MarkdownMathTests.cs
T
davideandClaude Sonnet 5.5 3587f35c2d Formule LaTeX nel markdown e documentazione senza esempi particolari
Le formule `$…$` e `$$…$$` si disegnano con CSharpMath (ADR-0008), con
ripiego sul sorgente se il LaTeX non è valido. I documenti e i nomi dei test
non citano più esempi di un solo dominio.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 15:31:28 +02:00

139 lines
4.7 KiB
C#

using Avalonia;
using Avalonia.Automation;
using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Headless.XUnit;
using Avalonia.Styling;
using Avalonia.Threading;
using Avalonia.VisualTree;
using CSharpMath.Avalonia;
using AgentWikiUi.Gui;
namespace AgentWikiUi.Tests;
/// <summary>Formule LaTeX nel markdown (ADR-0008): matrice MD-31…MD-38 in docs/TESTING.md.</summary>
[Trait("Category", "Gui")]
public sealed class MarkdownMathTests
{
static (Window Window, MarkdownView View) Show(string markdown, double width = 600)
{
var view = new MarkdownView();
var window = new Window { Width = width, Height = 800, Content = view };
window.Show();
view.Source = markdown;
Dispatcher.UIThread.RunJobs();
window.UpdateLayout();
return (window, view);
}
static List<MathView> Formulas(Visual v) => v.GetVisualDescendants().OfType<MathView>().ToList();
static string Text(Visual v) => string.Concat(v.GetVisualDescendants().OfType<TextBlock>()
.Select(t => t.Inlines is { Count: > 0 } ? string.Concat(t.Inlines.OfType<Run>().Select(r => r.Text)) : t.Text));
[AvaloniaFact]
public void Formula_inline()
{
var (_, view) = Show("Il gap è $E_g = E_{LUMO} - E_{HOMO}$ in eV.");
var f = Assert.Single(Formulas(view));
Assert.Equal("E_g = E_{LUMO} - E_{HOMO}", AutomationProperties.GetName(f));
Assert.True(string.IsNullOrEmpty(f.ErrorMessage));
Assert.True(f.Bounds.Width > 0 && f.Bounds.Height > 0);
var text = Text(view);
Assert.Contains("Il gap è", text);
Assert.Contains("in eV.", text);
Assert.DoesNotContain("$", text);
}
[AvaloniaFact]
public void Formula_a_blocco()
{
var (_, view) = Show("Prima.\n\n$$\n\\frac{a}{b} = c\n$$\n\nDopo.");
var f = Assert.Single(Formulas(view));
Assert.Equal("\\frac{a}{b} = c", AutomationProperties.GetName(f));
Assert.True(string.IsNullOrEmpty(f.ErrorMessage));
Assert.True(f.Bounds.Height > 0);
Assert.DoesNotContain("\\frac", Text(view)); // non è un blocco di codice col sorgente
Assert.Contains("Prima.", Text(view));
Assert.Contains("Dopo.", Text(view));
}
[AvaloniaTheory]
[InlineData("Testo $\\frac{a$ fine")]
[InlineData("$$\n\\unknowncommand{x}\n$$")]
[InlineData("Testo $\\begin{matrix$ fine")]
public void Formula_non_valida_ripiego(string markdown)
{
var (_, view) = Show(markdown);
Assert.Empty(Formulas(view));
Assert.Contains("$", Text(view)); // il sorgente resta visibile come testo
}
[AvaloniaTheory]
[InlineData("\\frac{a}{b}")]
[InlineData("x^2 + y_i")]
[InlineData("\\mathbf{A} \\times \\mathbf{B}")]
[InlineData("\\overline{x}")]
[InlineData("\\left( \\frac{1}{2} \\right)")]
[InlineData("\\lambda_{max} \\approx \\pi \\cdot \\tau")]
[InlineData("\\sum_{i=1}^{n} x_i")]
[InlineData("\\text{Mn} = \\chi \\varepsilon")]
public void Costrutti_latex_comuni(string latex)
{
var (_, view) = Show($"Prima $${latex}$$ dopo".Replace("$$", "$"));
var f = Assert.Single(Formulas(view));
Assert.Equal(latex, AutomationProperties.GetName(f));
Assert.True(string.IsNullOrEmpty(f.ErrorMessage), f.ErrorMessage);
Assert.True(f.Bounds.Width > 0);
}
[AvaloniaFact]
public void Formula_cambio_tema()
{
var (window, view) = Show("Gap $E_g$ e\n\n$$\\frac{a}{b}$$");
Assert.Equal(2, Formulas(view).Count);
window.RequestedThemeVariant = ThemeVariant.Dark;
Dispatcher.UIThread.RunJobs();
Assert.Equal(2, Formulas(view).Count);
window.RequestedThemeVariant = ThemeVariant.Light;
Dispatcher.UIThread.RunJobs();
Assert.Equal(2, Formulas(view).Count);
}
[AvaloniaFact]
public void Formula_in_contesti_annidati()
{
var markdown = """
Testo $a_1$ e un [link](https://example.com).
[vai a $b^2$](https://example.com)
- voce $c_3$
| x | y |
|---|---|
| $d_4$ | z |
""";
var (_, view) = Show(markdown);
Assert.Equal(4, Formulas(view).Count);
Assert.Contains("link", Text(view));
Assert.Contains("vai a", Text(view));
}
[AvaloniaFact]
public void Formula_nome_accessibile()
{
var (_, view) = Show("Gap $E_g$.");
var f = Assert.Single(Formulas(view));
Assert.Equal("E_g", AutomationProperties.GetName(f));
}
[AvaloniaFact]
public void Dollari_isolati_restano_testo()
{
var (_, view) = Show("Costa 10 $ e poi 20 $ in totale.");
Assert.Empty(Formulas(view));
Assert.Contains("10 $ e poi 20 $", Text(view));
}
}