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>
This commit is contained in:
1 parent
f2086de31d
commit
3587f35c2d
13 files changed
+297
-19
No files matched your search
@@ -0,0 +1,138 @@
|
||||
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));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user