| 1 | package cli |
| 2 | |
| 3 | import ( |
| 4 | "strings" |
| 5 | "testing" |
| 6 | |
| 7 | "github.com/charmbracelet/colorprofile" |
| 8 | ) |
| 9 | |
| 10 | func TestLatexToUnicode(t *testing.T) { |
| 11 | cases := []struct { |
| 12 | in, want string |
| 13 | }{ |
| 14 | {`E = mc^2`, "E = mc²"}, |
| 15 | {`x^{n+1}`, "xⁿ⁺¹"}, |
| 16 | {`H_2O`, "H₂O"}, |
| 17 | {`x_i^2`, "xᵢ²"}, |
| 18 | {`\alpha + \beta = \gamma`, "α + β = γ"}, |
| 19 | {`\sum_{i=1}^{n} i`, "∑ᵢ₌₁ⁿ i"}, |
| 20 | {`\int_0^1 x\,dx`, "∫₀¹ x dx"}, |
| 21 | {`\frac{1}{2}`, "1/2"}, |
| 22 | {`\frac{x+1}{2}`, "(x+1)/2"}, |
| 23 | {`\sqrt{2}`, "√2"}, |
| 24 | {`\sqrt{x+y}`, "√(x+y)"}, |
| 25 | {`\sqrt[3]{x}`, "∛x"}, |
| 26 | {`a \leq b \neq c`, "a ≤ b ≠ c"}, |
| 27 | {`\mathbb{R}^n`, "ℝⁿ"}, |
| 28 | {`\text{if } x > 0`, "if x > 0"}, |
| 29 | {`\vec{v}`, "v⃗"}, |
| 30 | {`a^q`, "a^q"}, |
| 31 | {`f(x) = x^{2y}`, "f(x) = x²ʸ"}, |
| 32 | } |
| 33 | for _, c := range cases { |
| 34 | if got := latexToUnicode(c.in); got != c.want { |
| 35 | t.Errorf("latexToUnicode(%q) = %q, want %q", c.in, got, c.want) |
| 36 | } |
| 37 | } |
| 38 | } |
| 39 | |
| 40 | func TestNormalizeMath(t *testing.T) { |
| 41 | cases := []struct { |
| 42 | in, want string |
| 43 | }{ |
| 44 | {`\(x+1\)`, "$x+1$"}, |
| 45 | {`\[x+1\]`, "$$x+1$$"}, |
| 46 | {"$$\nE = mc^2\n$$", "$$ E = mc^2 $$"}, |
| 47 | {"`\\(literal\\)`", "`\\(literal\\)`"}, |
| 48 | {"```\n\\[code\\]\n```", "```\n\\[code\\]\n```"}, |
| 49 | } |
| 50 | for _, c := range cases { |
| 51 | if got := normalizeMath(c.in); got != c.want { |
| 52 | t.Errorf("normalizeMath(%q) = %q, want %q", c.in, got, c.want) |
| 53 | } |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | func TestRenderInlineMath(t *testing.T) { |
| 58 | activeColorProfile = colorprofile.NoTTY |
| 59 | r := newMarkdownRenderer(80) |
| 60 | |
| 61 | out := r.Render(`The mass-energy relation is $E = mc^2$ exactly.`) |
| 62 | if !strings.Contains(out, "E = mc²") { |
| 63 | t.Errorf("inline math not rendered: %q", out) |
| 64 | } |
| 65 | |
| 66 | out = r.Render(`It costs $5 and then $10 total.`) |
| 67 | if !strings.Contains(out, "$5 and then $10") { |
| 68 | t.Errorf("currency wrongly parsed as math: %q", out) |
| 69 | } |
| 70 | |
| 71 | out = r.Render("$$\n\\int_0^1 x\\,dx = \\frac{1}{2}\n$$") |
| 72 | if !strings.Contains(out, "∫₀¹ x dx = 1/2") { |
| 73 | t.Errorf("display math not rendered: %q", out) |
| 74 | } |
| 75 | |
| 76 | out = r.Render("Code stays literal: `$x^2$` here.") |
| 77 | if !strings.Contains(out, "$x^2$") { |
| 78 | t.Errorf("math inside code span was converted: %q", out) |
| 79 | } |
| 80 | } |
| 81 |