mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-04 02:04:11 +01:00 
			
		
		
		
	* Fix #27645 * Add config options `MATH_CODE_BLOCK_DETECTION`, problematic syntaxes are disabled by default * Fix #33639 * Add config options `RENDER_OPTIONS_*`, old behaviors are kept
		
			
				
	
	
		
			311 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			311 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2024 The Gitea Authors. All rights reserved.
 | 
						|
// SPDX-License-Identifier: MIT
 | 
						|
 | 
						|
package markdown
 | 
						|
 | 
						|
import (
 | 
						|
	"strings"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"code.gitea.io/gitea/modules/markup"
 | 
						|
	"code.gitea.io/gitea/modules/setting"
 | 
						|
	"code.gitea.io/gitea/modules/test"
 | 
						|
 | 
						|
	"github.com/stretchr/testify/assert"
 | 
						|
)
 | 
						|
 | 
						|
const nl = "\n"
 | 
						|
 | 
						|
func TestMathRender(t *testing.T) {
 | 
						|
	setting.Markdown.MathCodeBlockOptions = setting.MarkdownMathCodeBlockOptions{ParseInlineDollar: true, ParseInlineParentheses: true}
 | 
						|
	testcases := []struct {
 | 
						|
		testcase string
 | 
						|
		expected string
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			"$a$",
 | 
						|
			`<p><code class="language-math">a</code></p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"$ a $",
 | 
						|
			`<p><code class="language-math">a</code></p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"$a$ $b$",
 | 
						|
			`<p><code class="language-math">a</code> <code class="language-math">b</code></p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			`\(a\) \(b\)`,
 | 
						|
			`<p><code class="language-math">a</code> <code class="language-math">b</code></p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			`$a$.`,
 | 
						|
			`<p><code class="language-math">a</code>.</p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			`.$a$`,
 | 
						|
			`<p>.$a$</p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			`$a a$b b$`,
 | 
						|
			`<p>$a a$b b$</p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			`a a$b b`,
 | 
						|
			`<p>a a$b b</p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			`a$b $a a$b b$`,
 | 
						|
			`<p>a$b $a a$b b$</p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"a$x$",
 | 
						|
			`<p>a$x$</p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"$x$a",
 | 
						|
			`<p>$x$a</p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"$a$ ($b$) [$c$] {$d$}",
 | 
						|
			`<p><code class="language-math">a</code> (<code class="language-math">b</code>) [$c$] {$d$}</p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"$$a$$",
 | 
						|
			`<p><code class="language-math">a</code></p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"$$a$$ test",
 | 
						|
			`<p><code class="language-math">a</code> test</p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"test $$a$$",
 | 
						|
			`<p>test <code class="language-math">a</code></p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			`foo $x=\$$ bar`,
 | 
						|
			`<p>foo <code class="language-math">x=\$</code> bar</p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			`$\text{$b$}$`,
 | 
						|
			`<p><code class="language-math">\text{$b$}</code></p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"a$`b`$c",
 | 
						|
			`<p>a<code class="language-math">b</code>c</p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"a $`b`$ c",
 | 
						|
			`<p>a <code class="language-math">b</code> c</p>` + nl,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"a$``b``$c x$```y```$z",
 | 
						|
			`<p>a<code class="language-math">b</code>c x<code class="language-math">y</code>z</p>` + nl,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, test := range testcases {
 | 
						|
		t.Run(test.testcase, func(t *testing.T) {
 | 
						|
			res, err := RenderString(markup.NewTestRenderContext(), test.testcase)
 | 
						|
			assert.NoError(t, err)
 | 
						|
			assert.Equal(t, test.expected, string(res))
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestMathRenderBlockIndent(t *testing.T) {
 | 
						|
	setting.Markdown.MathCodeBlockOptions = setting.MarkdownMathCodeBlockOptions{ParseBlockDollar: true, ParseBlockSquareBrackets: true}
 | 
						|
	testcases := []struct {
 | 
						|
		name     string
 | 
						|
		testcase string
 | 
						|
		expected string
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			"indent-0",
 | 
						|
			`
 | 
						|
\[
 | 
						|
\alpha
 | 
						|
\]
 | 
						|
`,
 | 
						|
			`<pre class="code-block is-loading"><code class="language-math display">
 | 
						|
\alpha
 | 
						|
</code></pre>
 | 
						|
`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"indent-1",
 | 
						|
			`
 | 
						|
 \[
 | 
						|
 \alpha
 | 
						|
 \]
 | 
						|
`,
 | 
						|
			`<pre class="code-block is-loading"><code class="language-math display">
 | 
						|
\alpha
 | 
						|
</code></pre>
 | 
						|
`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"indent-2-mismatch",
 | 
						|
			`
 | 
						|
  \[
 | 
						|
a
 | 
						|
 b
 | 
						|
  c
 | 
						|
   d
 | 
						|
  \]
 | 
						|
`,
 | 
						|
			`<pre class="code-block is-loading"><code class="language-math display">
 | 
						|
a
 | 
						|
b
 | 
						|
c
 | 
						|
 d
 | 
						|
</code></pre>
 | 
						|
`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"indent-2",
 | 
						|
			`
 | 
						|
  \[
 | 
						|
  a
 | 
						|
   b
 | 
						|
  c
 | 
						|
  \]
 | 
						|
`,
 | 
						|
			`<pre class="code-block is-loading"><code class="language-math display">
 | 
						|
a
 | 
						|
 b
 | 
						|
c
 | 
						|
</code></pre>
 | 
						|
`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"indent-0-oneline",
 | 
						|
			`$$ x $$
 | 
						|
foo`,
 | 
						|
			`<code class="language-math display"> x </code>
 | 
						|
<p>foo</p>
 | 
						|
`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"indent-3-oneline",
 | 
						|
			`   $$ x $$<SPACE>
 | 
						|
foo`,
 | 
						|
			`<code class="language-math display"> x </code>
 | 
						|
<p>foo</p>
 | 
						|
`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"quote-block",
 | 
						|
			`
 | 
						|
> \[
 | 
						|
> a
 | 
						|
> \]
 | 
						|
> \[
 | 
						|
> b
 | 
						|
> \]
 | 
						|
`,
 | 
						|
			`<blockquote>
 | 
						|
<pre class="code-block is-loading"><code class="language-math display">
 | 
						|
a
 | 
						|
</code></pre>
 | 
						|
<pre class="code-block is-loading"><code class="language-math display">
 | 
						|
b
 | 
						|
</code></pre>
 | 
						|
</blockquote>
 | 
						|
`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"list-block",
 | 
						|
			`
 | 
						|
1. a
 | 
						|
   \[
 | 
						|
   x
 | 
						|
   \]
 | 
						|
2. b`,
 | 
						|
			`<ol>
 | 
						|
<li>a
 | 
						|
<pre class="code-block is-loading"><code class="language-math display">
 | 
						|
x
 | 
						|
</code></pre>
 | 
						|
</li>
 | 
						|
<li>b</li>
 | 
						|
</ol>
 | 
						|
`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"inline-non-math",
 | 
						|
			`\[x]`,
 | 
						|
			`<p>[x]</p>` + nl,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, test := range testcases {
 | 
						|
		t.Run(test.name, func(t *testing.T) {
 | 
						|
			res, err := RenderString(markup.NewTestRenderContext(), strings.ReplaceAll(test.testcase, "<SPACE>", " "))
 | 
						|
			assert.NoError(t, err)
 | 
						|
			assert.Equal(t, test.expected, string(res), "unexpected result for test case:\n%s", test.testcase)
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestMathRenderOptions(t *testing.T) {
 | 
						|
	setting.Markdown.MathCodeBlockOptions = setting.MarkdownMathCodeBlockOptions{}
 | 
						|
	defer test.MockVariableValue(&setting.Markdown.MathCodeBlockOptions)
 | 
						|
	test := func(t *testing.T, expected, input string) {
 | 
						|
		res, err := RenderString(markup.NewTestRenderContext(), input)
 | 
						|
		assert.NoError(t, err)
 | 
						|
		assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(res)), "input: %s", input)
 | 
						|
	}
 | 
						|
 | 
						|
	// default (non-conflict) inline syntax
 | 
						|
	test(t, `<p><code class="language-math">a</code></p>`, "$`a`$")
 | 
						|
 | 
						|
	// ParseInlineDollar
 | 
						|
	test(t, `<p>$a$</p>`, `$a$`)
 | 
						|
	setting.Markdown.MathCodeBlockOptions.ParseInlineDollar = true
 | 
						|
	test(t, `<p><code class="language-math">a</code></p>`, `$a$`)
 | 
						|
 | 
						|
	// ParseInlineParentheses
 | 
						|
	test(t, `<p>(a)</p>`, `\(a\)`)
 | 
						|
	setting.Markdown.MathCodeBlockOptions.ParseInlineParentheses = true
 | 
						|
	test(t, `<p><code class="language-math">a</code></p>`, `\(a\)`)
 | 
						|
 | 
						|
	// ParseBlockDollar
 | 
						|
	test(t, `<p>$$
 | 
						|
a
 | 
						|
$$</p>
 | 
						|
`, `
 | 
						|
$$
 | 
						|
a
 | 
						|
$$
 | 
						|
`)
 | 
						|
	setting.Markdown.MathCodeBlockOptions.ParseBlockDollar = true
 | 
						|
	test(t, `<pre class="code-block is-loading"><code class="language-math display">
 | 
						|
a
 | 
						|
</code></pre>
 | 
						|
`, `
 | 
						|
$$
 | 
						|
a
 | 
						|
$$
 | 
						|
`)
 | 
						|
 | 
						|
	// ParseBlockSquareBrackets
 | 
						|
	test(t, `<p>[
 | 
						|
a
 | 
						|
]</p>
 | 
						|
`, `
 | 
						|
\[
 | 
						|
a
 | 
						|
\]
 | 
						|
`)
 | 
						|
	setting.Markdown.MathCodeBlockOptions.ParseBlockSquareBrackets = true
 | 
						|
	test(t, `<pre class="code-block is-loading"><code class="language-math display">
 | 
						|
a
 | 
						|
</code></pre>
 | 
						|
`, `
 | 
						|
\[
 | 
						|
a
 | 
						|
\]
 | 
						|
`)
 | 
						|
}
 |