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>
139 lines
4.7 KiB
C#
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));
|
|
}
|
|
}
|