mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-26 06:16:56 +09:00
test: consolidate Go tests (#39962)
Consolidate all Go tests. Coverage is identical to before. Go tests are around 5% faster while being 7% smaller. No non-test code is touched.
This commit is contained in:
1 parent
ce7364e215
commit
8abda62312
388 files changed
+18410
-29561
No files matched your search
+12
-21
@@ -21,27 +21,18 @@ func TestCamoHandleLink(t *testing.T) {
|
||||
setting.Camo.ServerURL = "https://image.proxy"
|
||||
setting.Camo.HMACKey = "geheim"
|
||||
dataURL := "data:image/png;base64,i//V"
|
||||
assert.Equal(t, dataURL, camoHandleLink(dataURL))
|
||||
|
||||
assert.Equal(t,
|
||||
"https://gitea.com/img.jpg",
|
||||
camoHandleLink("https://gitea.com/img.jpg"))
|
||||
assert.Equal(t,
|
||||
"https://testimages.org/img.jpg",
|
||||
camoHandleLink("https://testimages.org/img.jpg"))
|
||||
assert.Equal(t,
|
||||
"https://image.proxy/eivin43gJwGVIjR9MiYYtFIk0mw/aHR0cDovL3Rlc3RpbWFnZXMub3JnL2ltZy5qcGc",
|
||||
camoHandleLink("http://testimages.org/img.jpg"))
|
||||
test := func(expectedHTTPS string) {
|
||||
assert.Equal(t, dataURL, camoHandleLink(dataURL))
|
||||
assert.Equal(t,
|
||||
"https://gitea.com/img.jpg",
|
||||
camoHandleLink("https://gitea.com/img.jpg"))
|
||||
assert.Equal(t, expectedHTTPS, camoHandleLink("https://testimages.org/img.jpg"))
|
||||
assert.Equal(t,
|
||||
"https://image.proxy/eivin43gJwGVIjR9MiYYtFIk0mw/aHR0cDovL3Rlc3RpbWFnZXMub3JnL2ltZy5qcGc",
|
||||
camoHandleLink("http://testimages.org/img.jpg"))
|
||||
}
|
||||
|
||||
test("https://testimages.org/img.jpg")
|
||||
setting.Camo.Always = true
|
||||
assert.Equal(t, dataURL, camoHandleLink(dataURL))
|
||||
assert.Equal(t,
|
||||
"https://gitea.com/img.jpg",
|
||||
camoHandleLink("https://gitea.com/img.jpg"))
|
||||
assert.Equal(t,
|
||||
"https://image.proxy/tkdlvmqpbIr7SjONfHNgEU622y0/aHR0cHM6Ly90ZXN0aW1hZ2VzLm9yZy9pbWcuanBn",
|
||||
camoHandleLink("https://testimages.org/img.jpg"))
|
||||
assert.Equal(t,
|
||||
"https://image.proxy/eivin43gJwGVIjR9MiYYtFIk0mw/aHR0cDovL3Rlc3RpbWFnZXMub3JnL2ltZy5qcGc",
|
||||
camoHandleLink("http://testimages.org/img.jpg"))
|
||||
test("https://image.proxy/tkdlvmqpbIr7SjONfHNgEU622y0/aHR0cHM6Ly90ZXN0aW1hZ2VzLm9yZy9pbWcuanBn")
|
||||
}
|
||||
@@ -85,7 +85,6 @@ func TestRender_IssueIndexPattern(t *testing.T) {
|
||||
test("#abcd")
|
||||
test("test#1234")
|
||||
test("#1234test")
|
||||
test("#abcd")
|
||||
test("test!1234")
|
||||
test("!1234test")
|
||||
test(" test !1234test")
|
||||
@@ -257,16 +256,7 @@ func TestRender_IssueIndexPattern_NoShortPattern(t *testing.T) {
|
||||
testRenderIssueIndexPattern(t, "#1", "#1", NewTestRenderContext(metas))
|
||||
testRenderIssueIndexPattern(t, "#1312", "#1312", NewTestRenderContext(metas))
|
||||
testRenderIssueIndexPattern(t, "!1", "!1", NewTestRenderContext(metas))
|
||||
}
|
||||
|
||||
func TestRender_PostProcessIssueTitle(t *testing.T) {
|
||||
setting.AppURL = TestAppURL
|
||||
metas := map[string]string{
|
||||
"format": "https://someurl.com/{user}/{repo}/{index}",
|
||||
"user": "someUser",
|
||||
"repo": "someRepo",
|
||||
"style": IssueNameStyleNumeric,
|
||||
}
|
||||
actual := PostProcessIssueTitle(NewTestRenderContext(metas), "#1")
|
||||
assert.Equal(t, template.HTML("#1"), actual)
|
||||
}
|
||||
|
||||
@@ -37,43 +37,24 @@ func TestRender_IssueList(t *testing.T) {
|
||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(out)))
|
||||
}
|
||||
|
||||
t.Run("NormalIssueRef", func(t *testing.T) {
|
||||
test(
|
||||
"#12345",
|
||||
for _, tc := range []struct {
|
||||
name, input, expected string
|
||||
}{
|
||||
{
|
||||
"NormalIssueRef", "#12345",
|
||||
`<p><a href="/test-user/test-repo/issues/12345" class="ref-issue" rel="nofollow">#12345</a></p>`,
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("ListIssueRef", func(t *testing.T) {
|
||||
test(
|
||||
"* #12345",
|
||||
`<ul>
|
||||
},
|
||||
{"ListIssueRef", "* #12345", `<ul>
|
||||
<li><div>issue #12345</div></li>
|
||||
</ul>`,
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("ListIssueRefNormal", func(t *testing.T) {
|
||||
test(
|
||||
"* foo #12345 bar",
|
||||
`<ul>
|
||||
</ul>`},
|
||||
{"ListIssueRefNormal", "* foo #12345 bar", `<ul>
|
||||
<li>foo <a href="/test-user/test-repo/issues/12345" class="ref-issue" rel="nofollow">#12345</a> bar</li>
|
||||
</ul>`,
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("ListTodoIssueRef", func(t *testing.T) {
|
||||
test(
|
||||
"* [ ] #12345",
|
||||
`<ul>
|
||||
</ul>`},
|
||||
{"ListTodoIssueRef", "* [ ] #12345", `<ul>
|
||||
<li class="task-list-item"><input type="checkbox" disabled="" data-source-position="2"/><div>issue #12345</div></li>
|
||||
</ul>`,
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("IssueFootnote", func(t *testing.T) {
|
||||
test(
|
||||
"foo[^1][^2]\n\n[^1]: bar\n[^2]: baz",
|
||||
</ul>`},
|
||||
{
|
||||
"IssueFootnote", "foo[^1][^2]\n\n[^1]: bar\n[^2]: baz",
|
||||
`<p>foo<sup id="fnref:user-content-1-12345"><a href="#fn:user-content-1-12345" rel="nofollow">1 </a></sup><sup id="fnref:user-content-2-12345"><a href="#fn:user-content-2-12345" rel="nofollow">2 </a></sup></p>
|
||||
<div>
|
||||
<hr/>
|
||||
@@ -86,6 +67,10 @@ func TestRender_IssueList(t *testing.T) {
|
||||
</li>
|
||||
</ol>
|
||||
</div>`,
|
||||
)
|
||||
})
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(_t *testing.T) {
|
||||
test(tc.input, tc.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -11,94 +11,79 @@ import (
|
||||
)
|
||||
|
||||
func TestProcessNodeAttrID_HTMLHeadingWithoutID(t *testing.T) {
|
||||
// Test that HTML headings without id get an auto-generated id from their text content
|
||||
// when EnableHeadingIDGeneration is true (for repo files and wiki pages)
|
||||
testCases := []struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
name string
|
||||
generateHeadingID bool
|
||||
input, expected string
|
||||
}{
|
||||
// Test that HTML headings without id get an auto-generated id from their text content
|
||||
// when EnableHeadingIDGeneration is true (for repo files and wiki pages)
|
||||
{
|
||||
name: "h1 without id",
|
||||
input: `<h1>Heading without ID</h1>`,
|
||||
expected: `<h1 id="user-content-heading-without-id">Heading without ID</h1>`,
|
||||
"h1 without id", true,
|
||||
`<h1>Heading without ID</h1>`,
|
||||
`<h1 id="user-content-heading-without-id">Heading without ID</h1>`,
|
||||
},
|
||||
{
|
||||
name: "h2 without id",
|
||||
input: `<h2>Another Heading</h2>`,
|
||||
expected: `<h2 id="user-content-another-heading">Another Heading</h2>`,
|
||||
"h2 without id", true,
|
||||
`<h2>Another Heading</h2>`,
|
||||
`<h2 id="user-content-another-heading">Another Heading</h2>`,
|
||||
},
|
||||
{
|
||||
name: "h3 without id",
|
||||
input: `<h3>Third Level</h3>`,
|
||||
expected: `<h3 id="user-content-third-level">Third Level</h3>`,
|
||||
"h3 without id", true,
|
||||
`<h3>Third Level</h3>`,
|
||||
`<h3 id="user-content-third-level">Third Level</h3>`,
|
||||
},
|
||||
{
|
||||
name: "h1 with existing id should keep it",
|
||||
input: `<h1 id="my-custom-id">Heading with ID</h1>`,
|
||||
expected: `<h1 id="user-content-my-custom-id">Heading with ID</h1>`,
|
||||
"h1 with existing id should keep it", true,
|
||||
`<h1 id="my-custom-id">Heading with ID</h1>`,
|
||||
`<h1 id="user-content-my-custom-id">Heading with ID</h1>`,
|
||||
},
|
||||
{
|
||||
name: "h1 with user-content prefix should not double prefix",
|
||||
input: `<h1 id="user-content-already-prefixed">Already Prefixed</h1>`,
|
||||
expected: `<h1 id="user-content-already-prefixed">Already Prefixed</h1>`,
|
||||
"h1 with user-content prefix should not double prefix", true,
|
||||
`<h1 id="user-content-already-prefixed">Already Prefixed</h1>`,
|
||||
`<h1 id="user-content-already-prefixed">Already Prefixed</h1>`,
|
||||
},
|
||||
{
|
||||
name: "heading with special characters",
|
||||
input: `<h1>What is Wine Staging?</h1>`,
|
||||
expected: `<h1 id="user-content-what-is-wine-staging">What is Wine Staging?</h1>`,
|
||||
"heading with special characters", true,
|
||||
`<h1>What is Wine Staging?</h1>`,
|
||||
`<h1 id="user-content-what-is-wine-staging">What is Wine Staging?</h1>`,
|
||||
},
|
||||
{
|
||||
name: "heading with nested elements",
|
||||
input: `<h2><strong>Bold</strong> and <em>Italic</em></h2>`,
|
||||
expected: `<h2 id="user-content-bold-and-italic"><strong>Bold</strong> and <em>Italic</em></h2>`,
|
||||
"heading with nested elements", true,
|
||||
`<h2><strong>Bold</strong> and <em>Italic</em></h2>`,
|
||||
`<h2 id="user-content-bold-and-italic"><strong>Bold</strong> and <em>Italic</em></h2>`,
|
||||
},
|
||||
// Test that HTML headings in comment-like contexts (issue comments)
|
||||
// do NOT get auto-generated IDs to avoid duplicate IDs on pages with multiple documents.
|
||||
// This is controlled by EnableHeadingIDGeneration which defaults to false.
|
||||
// Default context without EnableHeadingIDGeneration (simulates comment rendering)
|
||||
{
|
||||
"h1 without id in comment context", false,
|
||||
`<h1>Heading without ID</h1>`,
|
||||
`<h1>Heading without ID</h1>`,
|
||||
},
|
||||
{
|
||||
"h2 without id in comment context", false,
|
||||
`<h2>Another Heading</h2>`,
|
||||
`<h2>Another Heading</h2>`,
|
||||
},
|
||||
{
|
||||
"h1 with existing id should still be prefixed", false,
|
||||
`<h1 id="my-custom-id">Heading with ID</h1>`,
|
||||
`<h1 id="user-content-my-custom-id">Heading with ID</h1>`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var result strings.Builder
|
||||
ctx := NewTestRenderContext().WithEnableHeadingIDGeneration(true)
|
||||
ctx := NewTestRenderContext()
|
||||
if tc.generateHeadingID {
|
||||
ctx.WithEnableHeadingIDGeneration(true)
|
||||
}
|
||||
err := PostProcessDefault(ctx, strings.NewReader(tc.input), &result)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tc.expected, strings.TrimSpace(result.String()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessNodeAttrID_SkipHeadingIDForComments(t *testing.T) {
|
||||
// Test that HTML headings in comment-like contexts (issue comments)
|
||||
// do NOT get auto-generated IDs to avoid duplicate IDs on pages with multiple documents.
|
||||
// This is controlled by EnableHeadingIDGeneration which defaults to false.
|
||||
testCases := []struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "h1 without id in comment context",
|
||||
input: `<h1>Heading without ID</h1>`,
|
||||
expected: `<h1>Heading without ID</h1>`,
|
||||
},
|
||||
{
|
||||
name: "h2 without id in comment context",
|
||||
input: `<h2>Another Heading</h2>`,
|
||||
expected: `<h2>Another Heading</h2>`,
|
||||
},
|
||||
{
|
||||
name: "h1 with existing id should still be prefixed",
|
||||
input: `<h1 id="my-custom-id">Heading with ID</h1>`,
|
||||
expected: `<h1 id="user-content-my-custom-id">Heading with ID</h1>`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var result strings.Builder
|
||||
// Default context without EnableHeadingIDGeneration (simulates comment rendering)
|
||||
err := PostProcessDefault(NewTestRenderContext(), strings.NewReader(tc.input), &result)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tc.expected, strings.TrimSpace(result.String()))
|
||||
})
|
||||
}
|
||||
}
|
||||
+120
-266
@@ -145,90 +145,42 @@ func TestRender_links(t *testing.T) {
|
||||
setting.Markdown.CustomURLSchemes = []string{"ftp", "magnet"}
|
||||
common.InitLinkURLSchemes(setting.Markdown.CustomURLSchemes)
|
||||
|
||||
// Text that should be turned into URL
|
||||
test(
|
||||
"https://www.example.com",
|
||||
`<p><a href="https://www.example.com" rel="nofollow">https://www.example.com</a></p>`)
|
||||
test(
|
||||
"http://www.example.com",
|
||||
`<p><a href="http://www.example.com" rel="nofollow">http://www.example.com</a></p>`)
|
||||
test(
|
||||
"https://example.com",
|
||||
`<p><a href="https://example.com" rel="nofollow">https://example.com</a></p>`)
|
||||
test(
|
||||
"http://example.com",
|
||||
`<p><a href="http://example.com" rel="nofollow">http://example.com</a></p>`)
|
||||
test(
|
||||
"http://foo.com/blah_blah",
|
||||
`<p><a href="http://foo.com/blah_blah" rel="nofollow">http://foo.com/blah_blah</a></p>`)
|
||||
test(
|
||||
"http://foo.com/blah_blah/",
|
||||
`<p><a href="http://foo.com/blah_blah/" rel="nofollow">http://foo.com/blah_blah/</a></p>`)
|
||||
test(
|
||||
"http://www.example.com/wpstyle/?p=364",
|
||||
`<p><a href="http://www.example.com/wpstyle/?p=364" rel="nofollow">http://www.example.com/wpstyle/?p=364</a></p>`)
|
||||
test(
|
||||
"https://www.example.com/foo/?bar=baz&inga=42&quux",
|
||||
`<p><a href="https://www.example.com/foo/?bar=baz&inga=42&quux" rel="nofollow">https://www.example.com/foo/?bar=baz&inga=42&quux</a></p>`)
|
||||
test(
|
||||
"http://142.42.1.1/",
|
||||
`<p><a href="http://142.42.1.1/" rel="nofollow">http://142.42.1.1/</a></p>`)
|
||||
test(
|
||||
"https://github.com/go-gitea/gitea/?p=aaa/bbb.html#ccc-ddd",
|
||||
`<p><a href="https://github.com/go-gitea/gitea/?p=aaa/bbb.html#ccc-ddd" rel="nofollow">https://github.com/go-gitea/gitea/?p=aaa/bbb.html#ccc-ddd</a></p>`)
|
||||
test(
|
||||
"https://en.wikipedia.org/wiki/URL_(disambiguation)",
|
||||
`<p><a href="https://en.wikipedia.org/wiki/URL_(disambiguation)" rel="nofollow">https://en.wikipedia.org/wiki/URL_(disambiguation)</a></p>`)
|
||||
test(
|
||||
"https://foo_bar.example.com/",
|
||||
`<p><a href="https://foo_bar.example.com/" rel="nofollow">https://foo_bar.example.com/</a></p>`)
|
||||
test(
|
||||
"https://stackoverflow.com/questions/2896191/what-is-go-used-fore",
|
||||
`<p><a href="https://stackoverflow.com/questions/2896191/what-is-go-used-fore" rel="nofollow">https://stackoverflow.com/questions/2896191/what-is-go-used-fore</a></p>`)
|
||||
test(
|
||||
"https://username:password@gitea.com",
|
||||
`<p><a href="https://username:password@gitea.com" rel="nofollow">https://username:password@gitea.com</a></p>`)
|
||||
test(
|
||||
"ftp://gitea.com/file.txt",
|
||||
`<p><a href="ftp://gitea.com/file.txt" rel="nofollow">ftp://gitea.com/file.txt</a></p>`)
|
||||
test(
|
||||
"magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download",
|
||||
`<p><a href="magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download" rel="nofollow">magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download</a></p>`)
|
||||
test(
|
||||
`[link](https://example.com)`,
|
||||
`<p><a href="https://example.com" rel="nofollow">link</a></p>`)
|
||||
test(
|
||||
`[link](mailto:test@example.com)`,
|
||||
`<p><a href="mailto:test@example.com" rel="nofollow">link</a></p>`)
|
||||
test(
|
||||
`[link](javascript:xss)`,
|
||||
`<p>link</p>`)
|
||||
for _, testCase := range []struct {
|
||||
input, expected string
|
||||
}{
|
||||
// Text that should be turned into URL
|
||||
{"https://www.example.com", `<p><a href="https://www.example.com" rel="nofollow">https://www.example.com</a></p>`},
|
||||
{"http://www.example.com", `<p><a href="http://www.example.com" rel="nofollow">http://www.example.com</a></p>`},
|
||||
{"https://example.com", `<p><a href="https://example.com" rel="nofollow">https://example.com</a></p>`},
|
||||
{"http://example.com", `<p><a href="http://example.com" rel="nofollow">http://example.com</a></p>`},
|
||||
{"http://foo.com/blah_blah", `<p><a href="http://foo.com/blah_blah" rel="nofollow">http://foo.com/blah_blah</a></p>`},
|
||||
{"http://foo.com/blah_blah/", `<p><a href="http://foo.com/blah_blah/" rel="nofollow">http://foo.com/blah_blah/</a></p>`},
|
||||
{"http://www.example.com/wpstyle/?p=364", `<p><a href="http://www.example.com/wpstyle/?p=364" rel="nofollow">http://www.example.com/wpstyle/?p=364</a></p>`},
|
||||
{"https://www.example.com/foo/?bar=baz&inga=42&quux", `<p><a href="https://www.example.com/foo/?bar=baz&inga=42&quux" rel="nofollow">https://www.example.com/foo/?bar=baz&inga=42&quux</a></p>`},
|
||||
{"http://142.42.1.1/", `<p><a href="http://142.42.1.1/" rel="nofollow">http://142.42.1.1/</a></p>`},
|
||||
{"https://github.com/go-gitea/gitea/?p=aaa/bbb.html#ccc-ddd", `<p><a href="https://github.com/go-gitea/gitea/?p=aaa/bbb.html#ccc-ddd" rel="nofollow">https://github.com/go-gitea/gitea/?p=aaa/bbb.html#ccc-ddd</a></p>`},
|
||||
{"https://en.wikipedia.org/wiki/URL_(disambiguation)", `<p><a href="https://en.wikipedia.org/wiki/URL_(disambiguation)" rel="nofollow">https://en.wikipedia.org/wiki/URL_(disambiguation)</a></p>`},
|
||||
{"https://foo_bar.example.com/", `<p><a href="https://foo_bar.example.com/" rel="nofollow">https://foo_bar.example.com/</a></p>`},
|
||||
{"https://stackoverflow.com/questions/2896191/what-is-go-used-fore", `<p><a href="https://stackoverflow.com/questions/2896191/what-is-go-used-fore" rel="nofollow">https://stackoverflow.com/questions/2896191/what-is-go-used-fore</a></p>`},
|
||||
{"https://username:password@gitea.com", `<p><a href="https://username:password@gitea.com" rel="nofollow">https://username:password@gitea.com</a></p>`},
|
||||
{"ftp://gitea.com/file.txt", `<p><a href="ftp://gitea.com/file.txt" rel="nofollow">ftp://gitea.com/file.txt</a></p>`},
|
||||
{"magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download", `<p><a href="magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download" rel="nofollow">magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download</a></p>`},
|
||||
{`[link](https://example.com)`, `<p><a href="https://example.com" rel="nofollow">link</a></p>`},
|
||||
{`[link](mailto:test@example.com)`, `<p><a href="mailto:test@example.com" rel="nofollow">link</a></p>`},
|
||||
{`[link](javascript:xss)`, `<p>link</p>`},
|
||||
|
||||
// Test that should *not* be turned into URL
|
||||
test(
|
||||
"www.example.com",
|
||||
`<p>www.example.com</p>`)
|
||||
test(
|
||||
"example.com",
|
||||
`<p>example.com</p>`)
|
||||
test(
|
||||
"test.example.com",
|
||||
`<p>test.example.com</p>`)
|
||||
test(
|
||||
"http://",
|
||||
`<p>http://</p>`)
|
||||
test(
|
||||
"https://",
|
||||
`<p>https://</p>`)
|
||||
test(
|
||||
"://",
|
||||
`<p>://</p>`)
|
||||
test(
|
||||
"www",
|
||||
`<p>www</p>`)
|
||||
test(
|
||||
"ftps://gitea.com",
|
||||
`<p>ftps://gitea.com</p>`)
|
||||
// Test that should *not* be turned into URL
|
||||
{"www.example.com", `<p>www.example.com</p>`},
|
||||
{"example.com", `<p>example.com</p>`},
|
||||
{"test.example.com", `<p>test.example.com</p>`},
|
||||
{"http://", `<p>http://</p>`},
|
||||
{"https://", `<p>https://</p>`},
|
||||
{"://", `<p>://</p>`},
|
||||
{"www", `<p>www</p>`},
|
||||
{"ftps://gitea.com", `<p>ftps://gitea.com</p>`},
|
||||
} {
|
||||
test(testCase.input, testCase.expected)
|
||||
}
|
||||
|
||||
t.Run("LinkEllipsis", func(t *testing.T) {
|
||||
input := util.EllipsisDisplayString("http://10.1.2.3", 12)
|
||||
@@ -244,73 +196,41 @@ func TestRender_links(t *testing.T) {
|
||||
func TestRender_email(t *testing.T) {
|
||||
setting.AppURL = markup.TestAppURL
|
||||
defer testModule.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
|
||||
test := func(input, expected string) {
|
||||
res, err := testRenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), input)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res), "input: %s", input)
|
||||
}
|
||||
for _, testCase := range []struct {
|
||||
input, expected string
|
||||
}{
|
||||
// Text that should be turned into email link
|
||||
{"info@gitea.com", `<p><a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a></p>`},
|
||||
{"(info@gitea.com)", `<p>(<a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>)</p>`},
|
||||
{"[info@gitea.com]", `<p>[<a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>]</p>`},
|
||||
{"info@gitea.com.", `<p><a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>.</p>`},
|
||||
{"firstname+lastname@gitea.com", `<p><a href="mailto:firstname+lastname@gitea.com" rel="nofollow">firstname+lastname@gitea.com</a></p>`},
|
||||
{"send email to info@gitea.co.uk.", `<p>send email to <a href="mailto:info@gitea.co.uk" rel="nofollow">info@gitea.co.uk</a>.</p>`},
|
||||
|
||||
// Text that should be turned into email link
|
||||
test(
|
||||
"info@gitea.com",
|
||||
`<p><a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a></p>`)
|
||||
test(
|
||||
"(info@gitea.com)",
|
||||
`<p>(<a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>)</p>`)
|
||||
test(
|
||||
"[info@gitea.com]",
|
||||
`<p>[<a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>]</p>`)
|
||||
test(
|
||||
"info@gitea.com.",
|
||||
`<p><a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>.</p>`)
|
||||
test(
|
||||
"firstname+lastname@gitea.com",
|
||||
`<p><a href="mailto:firstname+lastname@gitea.com" rel="nofollow">firstname+lastname@gitea.com</a></p>`)
|
||||
test(
|
||||
"send email to info@gitea.co.uk.",
|
||||
`<p>send email to <a href="mailto:info@gitea.co.uk" rel="nofollow">info@gitea.co.uk</a>.</p>`)
|
||||
|
||||
test(
|
||||
`j.doe@example.com,
|
||||
{`j.doe@example.com,
|
||||
j.doe@example.com.
|
||||
j.doe@example.com;
|
||||
j.doe@example.com?
|
||||
j.doe@example.com!`,
|
||||
`<p><a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>,
|
||||
j.doe@example.com!`, `<p><a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>,
|
||||
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>.
|
||||
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>;
|
||||
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>?
|
||||
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>!</p>`)
|
||||
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>!</p>`},
|
||||
|
||||
// match GitHub behavior
|
||||
test("email@domain@domain.com", `<p>email@<a href="mailto:domain@domain.com" rel="nofollow">domain@domain.com</a></p>`)
|
||||
// match GitHub behavior
|
||||
{"email@domain@domain.com", `<p>email@<a href="mailto:domain@domain.com" rel="nofollow">domain@domain.com</a></p>`},
|
||||
|
||||
// match GitHub behavior
|
||||
test(`"info@gitea.com"`, `<p>"<a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>"</p>`)
|
||||
// match GitHub behavior
|
||||
{`"info@gitea.com"`, `<p>"<a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>"</p>`},
|
||||
|
||||
// Test that should *not* be turned into email links
|
||||
test(
|
||||
"/home/gitea/mailstore/info@gitea/com",
|
||||
`<p>/home/gitea/mailstore/info@gitea/com</p>`)
|
||||
test(
|
||||
"git@try.gitea.io:go-gitea/gitea.git",
|
||||
`<p>git@try.gitea.io:go-gitea/gitea.git</p>`)
|
||||
test(
|
||||
"https://foo:bar@gitea.io",
|
||||
`<p><a href="https://foo:bar@gitea.io" rel="nofollow">https://foo:bar@gitea.io</a></p>`)
|
||||
test(
|
||||
"gitea@3",
|
||||
`<p>gitea@3</p>`)
|
||||
test(
|
||||
"gitea@gmail.c",
|
||||
`<p>gitea@gmail.c</p>`)
|
||||
test(
|
||||
"email@domain..com",
|
||||
`<p>email@domain..com</p>`)
|
||||
// Test that should *not* be turned into email links
|
||||
{"/home/gitea/mailstore/info@gitea/com", `<p>/home/gitea/mailstore/info@gitea/com</p>`},
|
||||
{"git@try.gitea.io:go-gitea/gitea.git", `<p>git@try.gitea.io:go-gitea/gitea.git</p>`},
|
||||
{"https://foo:bar@gitea.io", `<p><a href="https://foo:bar@gitea.io" rel="nofollow">https://foo:bar@gitea.io</a></p>`},
|
||||
{"gitea@3", `<p>gitea@3</p>`},
|
||||
{"gitea@gmail.c", `<p>gitea@gmail.c</p>`},
|
||||
{"email@domain..com", `<p>email@domain..com</p>`},
|
||||
|
||||
cases := []struct {
|
||||
input, expected string
|
||||
}{
|
||||
// match GitHub behavior
|
||||
{"?a@d.zz", `<p>?<a href="mailto:a@d.zz" rel="nofollow">a@d.zz</a></p>`},
|
||||
{"*a@d.zz", `<p>*<a href="mailto:a@d.zz" rel="nofollow">a@d.zz</a></p>`},
|
||||
@@ -320,9 +240,10 @@ func TestRender_email(t *testing.T) {
|
||||
// maybe we should reduce the candidate characters for the "name" part in the future
|
||||
{"a*a@d.zz", `<p><a href="mailto:a*a@d.zz" rel="nofollow">a*a@d.zz</a></p>`},
|
||||
{"a~a@d.zz", `<p><a href="mailto:a~a@d.zz" rel="nofollow">a~a@d.zz</a></p>`},
|
||||
}
|
||||
for _, c := range cases {
|
||||
test(c.input, c.expected)
|
||||
} {
|
||||
res, err := testRenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), testCase.input)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, strings.TrimSpace(testCase.expected), strings.TrimSpace(res), "input: %s", testCase.input)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,12 +315,6 @@ func TestRender_ShortLinks(t *testing.T) {
|
||||
setting.AppURL = markup.TestAppURL
|
||||
tree := markup.TestRepoURL + "src/master"
|
||||
|
||||
test := func(input, expected string) {
|
||||
buffer, err := markdown.RenderString(markup.NewTestRenderContext(tree), input)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
|
||||
}
|
||||
|
||||
url := tree + "/Link"
|
||||
otherURL := tree + "/Other-Link"
|
||||
encodedURL := tree + "/Link%3F"
|
||||
@@ -410,88 +325,36 @@ func TestRender_ShortLinks(t *testing.T) {
|
||||
renderableFileURL := tree + "/markdown_file.md"
|
||||
unrenderableFileURL := tree + "/file.zip"
|
||||
favicon := "http://google.com/favicon.ico"
|
||||
test(
|
||||
"[[Link]]",
|
||||
`<p><a href="`+url+`" rel="nofollow">Link</a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[Link.-]]",
|
||||
`<p><a href="http://localhost:3000/test-owner/test-repo/src/master/Link.-" rel="nofollow">Link.-</a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[Link.jpg]]",
|
||||
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Link.jpg" alt="Link.jpg"/></a></p>`,
|
||||
)
|
||||
test(
|
||||
"[["+favicon+"]]",
|
||||
`<p><a href="`+favicon+`" rel="nofollow"><img src="`+favicon+`" title="favicon.ico" alt="`+favicon+`"/></a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[Name|Link]]",
|
||||
`<p><a href="`+url+`" rel="nofollow">Name</a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[Name|Link.jpg]]",
|
||||
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Name" alt="Name"/></a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[Name|Link.jpg|alt=AltName]]",
|
||||
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="AltName" alt="AltName"/></a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[Name|Link.jpg|title=Title]]",
|
||||
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Title" alt="Title"/></a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[Name|Link.jpg|alt=AltName|title=Title]]",
|
||||
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Title" alt="AltName"/></a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[Name|Link.jpg|alt=\"AltName\"|title='Title']]",
|
||||
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Title" alt="AltName"/></a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[Name|Link Other.jpg|alt=\"AltName\"|title='Title']]",
|
||||
`<p><a href="`+otherImgurl+`" rel="nofollow"><img src="`+otherImgurl+`" title="Title" alt="AltName"/></a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[Link]] [[Other Link]]",
|
||||
`<p><a href="`+url+`" rel="nofollow">Link</a> <a href="`+otherURL+`" rel="nofollow">Other Link</a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[Link?]]",
|
||||
`<p><a href="`+encodedURL+`" rel="nofollow">Link?</a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[Link]] [[Other Link]] [[Link?]]",
|
||||
`<p><a href="`+url+`" rel="nofollow">Link</a> <a href="`+otherURL+`" rel="nofollow">Other Link</a> <a href="`+encodedURL+`" rel="nofollow">Link?</a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[markdown_file.md]]",
|
||||
`<p><a href="`+renderableFileURL+`" rel="nofollow">markdown_file.md</a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[file.zip]]",
|
||||
`<p><a href="`+unrenderableFileURL+`" rel="nofollow">file.zip</a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[Link #.jpg]]",
|
||||
`<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`" title="Link #.jpg" alt="Link #.jpg"/></a></p>`,
|
||||
)
|
||||
test(
|
||||
"[[Name|Link #.jpg|alt=\"AltName\"|title='Title']]",
|
||||
`<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`" title="Title" alt="AltName"/></a></p>`,
|
||||
)
|
||||
// FIXME: it's unable to resolve: [[link?k=v]]
|
||||
// FIXME: it is a wrong test case, it is not an image, but a link with anchor "#.jpg"
|
||||
test(
|
||||
"[[some/path/Link #.jpg]]",
|
||||
`<p><a href="`+notencodedImgurl+`" rel="nofollow"><img src="`+notencodedImgurl+`" title="Link #.jpg" alt="some/path/Link #.jpg"/></a></p>`,
|
||||
)
|
||||
test(
|
||||
"<p><a href=\"https://example.org\">[[foobar]]</a></p>",
|
||||
`<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`,
|
||||
)
|
||||
for _, testCase := range []struct {
|
||||
input, expected string
|
||||
}{
|
||||
{"[[Link]]", `<p><a href="` + url + `" rel="nofollow">Link</a></p>`},
|
||||
{"[[Link.-]]", `<p><a href="http://localhost:3000/test-owner/test-repo/src/master/Link.-" rel="nofollow">Link.-</a></p>`},
|
||||
{"[[Link.jpg]]", `<p><a href="` + imgurl + `" rel="nofollow"><img src="` + imgurl + `" title="Link.jpg" alt="Link.jpg"/></a></p>`},
|
||||
{"[[" + favicon + "]]", `<p><a href="` + favicon + `" rel="nofollow"><img src="` + favicon + `" title="favicon.ico" alt="` + favicon + `"/></a></p>`},
|
||||
{"[[Name|Link]]", `<p><a href="` + url + `" rel="nofollow">Name</a></p>`},
|
||||
{"[[Name|Link.jpg]]", `<p><a href="` + imgurl + `" rel="nofollow"><img src="` + imgurl + `" title="Name" alt="Name"/></a></p>`},
|
||||
{"[[Name|Link.jpg|alt=AltName]]", `<p><a href="` + imgurl + `" rel="nofollow"><img src="` + imgurl + `" title="AltName" alt="AltName"/></a></p>`},
|
||||
{"[[Name|Link.jpg|title=Title]]", `<p><a href="` + imgurl + `" rel="nofollow"><img src="` + imgurl + `" title="Title" alt="Title"/></a></p>`},
|
||||
{"[[Name|Link.jpg|alt=AltName|title=Title]]", `<p><a href="` + imgurl + `" rel="nofollow"><img src="` + imgurl + `" title="Title" alt="AltName"/></a></p>`},
|
||||
{"[[Name|Link.jpg|alt=\"AltName\"|title='Title']]", `<p><a href="` + imgurl + `" rel="nofollow"><img src="` + imgurl + `" title="Title" alt="AltName"/></a></p>`},
|
||||
{"[[Name|Link Other.jpg|alt=\"AltName\"|title='Title']]", `<p><a href="` + otherImgurl + `" rel="nofollow"><img src="` + otherImgurl + `" title="Title" alt="AltName"/></a></p>`},
|
||||
{"[[Link]] [[Other Link]]", `<p><a href="` + url + `" rel="nofollow">Link</a> <a href="` + otherURL + `" rel="nofollow">Other Link</a></p>`},
|
||||
{"[[Link?]]", `<p><a href="` + encodedURL + `" rel="nofollow">Link?</a></p>`},
|
||||
{"[[Link]] [[Other Link]] [[Link?]]", `<p><a href="` + url + `" rel="nofollow">Link</a> <a href="` + otherURL + `" rel="nofollow">Other Link</a> <a href="` + encodedURL + `" rel="nofollow">Link?</a></p>`},
|
||||
{"[[markdown_file.md]]", `<p><a href="` + renderableFileURL + `" rel="nofollow">markdown_file.md</a></p>`},
|
||||
{"[[file.zip]]", `<p><a href="` + unrenderableFileURL + `" rel="nofollow">file.zip</a></p>`},
|
||||
{"[[Link #.jpg]]", `<p><a href="` + encodedImgurl + `" rel="nofollow"><img src="` + encodedImgurl + `" title="Link #.jpg" alt="Link #.jpg"/></a></p>`},
|
||||
{"[[Name|Link #.jpg|alt=\"AltName\"|title='Title']]", `<p><a href="` + encodedImgurl + `" rel="nofollow"><img src="` + encodedImgurl + `" title="Title" alt="AltName"/></a></p>`},
|
||||
// FIXME: it's unable to resolve: [[link?k=v]]
|
||||
// FIXME: it is a wrong test case, it is not an image, but a link with anchor "#.jpg"
|
||||
{"[[some/path/Link #.jpg]]", `<p><a href="` + notencodedImgurl + `" rel="nofollow"><img src="` + notencodedImgurl + `" title="Link #.jpg" alt="some/path/Link #.jpg"/></a></p>`},
|
||||
{"<p><a href=\"https://example.org\">[[foobar]]</a></p>", `<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`},
|
||||
} {
|
||||
buffer, err := markdown.RenderString(markup.NewTestRenderContext(tree), testCase.input)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, strings.TrimSpace(testCase.expected), strings.TrimSpace(string(buffer)))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ParseClusterFuzz(t *testing.T) {
|
||||
@@ -519,45 +382,36 @@ func TestPostProcess(t *testing.T) {
|
||||
setting.StaticURLPrefix = strings.TrimSuffix(markup.TestAppURL, "/") // can't run standalone
|
||||
defer testModule.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
|
||||
|
||||
test := func(input, expected string) {
|
||||
for _, testCase := range []struct {
|
||||
input, expected string
|
||||
}{
|
||||
// Issue index shouldn't be post-processing in a document.
|
||||
{"#1", "#1"},
|
||||
|
||||
// But cross-referenced issue index should work.
|
||||
{"go-gitea/gitea#12345", `<a href="/go-gitea/gitea/issues/12345" class="ref-issue">go-gitea/gitea#12345</a>`},
|
||||
|
||||
// Test that other post-processing still works.
|
||||
{":gitea:", `<span class="emoji"><img alt=":gitea:" src="` + setting.StaticURLPrefix + `/assets/img/emoji/gitea.png"/></span>`},
|
||||
{"Some text with 😄 in the middle", `Some text with <span class="emoji" data-alias="smile">😄</span> in the middle`},
|
||||
{"http://localhost:3000/person/repo/issues/4#issuecomment-1234", `<a href="http://localhost:3000/person/repo/issues/4#issuecomment-1234" class="ref-issue">person/repo#4 (comment)</a>`},
|
||||
{"<math><mtext>:gitea: go-gitea/gitea#12345</mtext></math>", "<math><mtext>:gitea: go-gitea/gitea#12345</mtext></math>"},
|
||||
|
||||
// special tags, GitHub's behavior, and for unclosed tags, output as text content as much as possible
|
||||
{"<script>a", `<script>a`},
|
||||
{"<script>a</script>", `<script>a</script>`},
|
||||
{"<STYLE>a", `<STYLE>a`},
|
||||
{"<style>a</STYLE>", `<style>a</STYLE>`},
|
||||
|
||||
// other special tags, our special behavior
|
||||
{"<?php\nfoo", "<?php\nfoo"},
|
||||
{"<%asp\nfoo", "<%asp\nfoo"},
|
||||
} {
|
||||
var res strings.Builder
|
||||
err := markup.PostProcessDefault(markup.NewTestRenderContext(markup.TestAppURL, map[string]string{"user": "go-gitea", "repo": "gitea"}), strings.NewReader(input), &res)
|
||||
err := markup.PostProcessDefault(markup.NewTestRenderContext(markup.TestAppURL, map[string]string{"user": "go-gitea", "repo": "gitea"}), strings.NewReader(testCase.input), &res)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res.String()))
|
||||
assert.Equal(t, strings.TrimSpace(testCase.expected), strings.TrimSpace(res.String()))
|
||||
}
|
||||
|
||||
// Issue index shouldn't be post-processing in a document.
|
||||
test(
|
||||
"#1",
|
||||
"#1")
|
||||
|
||||
// But cross-referenced issue index should work.
|
||||
test(
|
||||
"go-gitea/gitea#12345",
|
||||
`<a href="/go-gitea/gitea/issues/12345" class="ref-issue">go-gitea/gitea#12345</a>`)
|
||||
|
||||
// Test that other post-processing still works.
|
||||
test(
|
||||
":gitea:",
|
||||
`<span class="emoji"><img alt=":gitea:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/gitea.png"/></span>`)
|
||||
test(
|
||||
"Some text with 😄 in the middle",
|
||||
`Some text with <span class="emoji" data-alias="smile">😄</span> in the middle`)
|
||||
test("http://localhost:3000/person/repo/issues/4#issuecomment-1234",
|
||||
`<a href="http://localhost:3000/person/repo/issues/4#issuecomment-1234" class="ref-issue">person/repo#4 (comment)</a>`)
|
||||
test(
|
||||
"<math><mtext>:gitea: go-gitea/gitea#12345</mtext></math>",
|
||||
"<math><mtext>:gitea: go-gitea/gitea#12345</mtext></math>")
|
||||
|
||||
// special tags, GitHub's behavior, and for unclosed tags, output as text content as much as possible
|
||||
test("<script>a", `<script>a`)
|
||||
test("<script>a</script>", `<script>a</script>`)
|
||||
test("<STYLE>a", `<STYLE>a`)
|
||||
test("<style>a</STYLE>", `<style>a</STYLE>`)
|
||||
|
||||
// other special tags, our special behavior
|
||||
test("<?php\nfoo", "<?php\nfoo")
|
||||
test("<%asp\nfoo", "<%asp\nfoo")
|
||||
}
|
||||
|
||||
func TestIssue16020(t *testing.T) {
|
||||
|
||||
@@ -61,30 +61,20 @@ func TestRenderInternalAttrs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRenderInternalExtraHead(t *testing.T) {
|
||||
t.Run("HeadExists", func(t *testing.T) {
|
||||
out := &bytes.Buffer{}
|
||||
var r RenderInternal
|
||||
in := r.init("sec", out, `<MY-TAG>`)
|
||||
_, _ = io.WriteString(in, `<head>any</head>`)
|
||||
_ = in.Close()
|
||||
assert.Equal(t, `<head><MY-TAG>any</head>`, out.String())
|
||||
})
|
||||
|
||||
t.Run("HeadNotExists", func(t *testing.T) {
|
||||
out := &bytes.Buffer{}
|
||||
var r RenderInternal
|
||||
in := r.init("sec", out, `<MY-TAG>`)
|
||||
_, _ = io.WriteString(in, `<div></div>`)
|
||||
_ = in.Close()
|
||||
assert.Equal(t, `<MY-TAG><div></div>`, out.String())
|
||||
})
|
||||
|
||||
t.Run("NotHTML", func(t *testing.T) {
|
||||
out := &bytes.Buffer{}
|
||||
var r RenderInternal
|
||||
in := r.init("sec", out, `<MY-TAG>`)
|
||||
_, _ = io.WriteString(in, `<any>`)
|
||||
_ = in.Close()
|
||||
assert.Equal(t, `<any>`, out.String())
|
||||
})
|
||||
for _, test := range []struct {
|
||||
name, input, expected string
|
||||
}{
|
||||
{"HeadExists", `<head>any</head>`, `<head><MY-TAG>any</head>`},
|
||||
{"HeadNotExists", `<div></div>`, `<MY-TAG><div></div>`},
|
||||
{"NotHTML", `<any>`, `<any>`},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
out := &bytes.Buffer{}
|
||||
var r RenderInternal
|
||||
in := r.init("sec", out, `<MY-TAG>`)
|
||||
_, _ = io.WriteString(in, test.input)
|
||||
_ = in.Close()
|
||||
assert.Equal(t, test.expected, out.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,12 @@ import (
|
||||
|
||||
func TestRender(t *testing.T) {
|
||||
r := renderer{}
|
||||
render := func(t *testing.T, ctx *markup.RenderContext, input string) string {
|
||||
var output strings.Builder
|
||||
err := r.Render(ctx, strings.NewReader(input), &output)
|
||||
assert.NoError(t, err)
|
||||
return output.String()
|
||||
}
|
||||
|
||||
t.Run("Basic notebook", func(t *testing.T) {
|
||||
input := `{
|
||||
@@ -37,12 +43,7 @@ func TestRender(t *testing.T) {
|
||||
"nbformat": 4
|
||||
}`
|
||||
|
||||
var output strings.Builder
|
||||
ctx := &markup.RenderContext{}
|
||||
err := r.Render(ctx, strings.NewReader(input), &output)
|
||||
|
||||
assert.NoError(t, err)
|
||||
result := output.String()
|
||||
result := render(t, &markup.RenderContext{}, input)
|
||||
assert.Contains(t, result, `<div class="jupyter-notebook">`)
|
||||
assert.Contains(t, result, `<div class="notebook-cell cell-type-code">`)
|
||||
assert.Contains(t, result, `In [1]:`)
|
||||
@@ -68,12 +69,7 @@ func TestRender(t *testing.T) {
|
||||
"nbformat": 4
|
||||
}`
|
||||
|
||||
var output strings.Builder
|
||||
ctx := markup.NewRenderContext(t.Context())
|
||||
err := r.Render(ctx, strings.NewReader(input), &output)
|
||||
|
||||
assert.NoError(t, err)
|
||||
result := output.String()
|
||||
result := render(t, markup.NewRenderContext(t.Context()), input)
|
||||
|
||||
// Assert normal markup still renders correctly
|
||||
assert.Contains(t, result, `<div class="notebook-cell cell-type-markdown">`)
|
||||
@@ -94,12 +90,7 @@ func TestRender(t *testing.T) {
|
||||
}
|
||||
input := fmt.Sprintf(`{"cells": [%s], "metadata": {}, "nbformat": 4}`, strings.Join(cellBlocks, ","))
|
||||
|
||||
var output strings.Builder
|
||||
ctx := markup.NewRenderContext(t.Context())
|
||||
err := r.Render(ctx, strings.NewReader(input), &output)
|
||||
|
||||
assert.NoError(t, err)
|
||||
result := output.String()
|
||||
result := render(t, markup.NewRenderContext(t.Context()), input)
|
||||
|
||||
// Verify it halts rendering gracefully and shows the truncation warning
|
||||
assert.Contains(t, result, "Output truncated.")
|
||||
@@ -130,12 +121,7 @@ func TestRender(t *testing.T) {
|
||||
"nbformat": 4
|
||||
}`
|
||||
|
||||
var output strings.Builder
|
||||
ctx := markup.NewRenderContext(t.Context())
|
||||
err := r.Render(ctx, strings.NewReader(input), &output)
|
||||
|
||||
assert.NoError(t, err)
|
||||
result := output.String()
|
||||
result := render(t, markup.NewRenderContext(t.Context()), input)
|
||||
assert.Contains(t, result, `<img src="data:image/png;base64,`)
|
||||
assert.Contains(t, result, `iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==`)
|
||||
})
|
||||
@@ -161,12 +147,7 @@ func TestRender(t *testing.T) {
|
||||
"nbformat": 4
|
||||
}`
|
||||
|
||||
var output strings.Builder
|
||||
ctx := markup.NewRenderContext(t.Context())
|
||||
err := r.Render(ctx, strings.NewReader(input), &output)
|
||||
|
||||
assert.NoError(t, err)
|
||||
result := output.String()
|
||||
result := render(t, markup.NewRenderContext(t.Context()), input)
|
||||
assert.NotContains(t, result, `<style scoped>`)
|
||||
assert.Contains(t, result, `<table><tr><td>1</td></tr></table>`)
|
||||
assert.Contains(t, result, `<td>1</td>`)
|
||||
@@ -193,12 +174,7 @@ func TestRender(t *testing.T) {
|
||||
"nbformat": 4
|
||||
}`
|
||||
|
||||
var output strings.Builder
|
||||
ctx := markup.NewRenderContext(t.Context())
|
||||
err := r.Render(ctx, strings.NewReader(input), &output)
|
||||
|
||||
assert.NoError(t, err)
|
||||
result := output.String()
|
||||
result := render(t, markup.NewRenderContext(t.Context()), input)
|
||||
assert.Contains(t, result, `ValueError: test error`)
|
||||
assert.Contains(t, result, `cell-output-error`)
|
||||
})
|
||||
@@ -210,12 +186,8 @@ func TestRender(t *testing.T) {
|
||||
"nbformat": 3
|
||||
}`
|
||||
|
||||
var output strings.Builder
|
||||
ctx := markup.NewRenderContext(t.Context())
|
||||
err := r.Render(ctx, strings.NewReader(input), &output)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Regexp(t, `<div class="file-not-rendered-prompt">This notebook uses an older format.*</div>`, output.String())
|
||||
result := render(t, markup.NewRenderContext(t.Context()), input)
|
||||
assert.Regexp(t, `<div class="file-not-rendered-prompt">This notebook uses an older format.*</div>`, result)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -58,17 +58,6 @@ func TestRender_Images(t *testing.T) {
|
||||
result := baseLink + "/.images/src/02/train.jpg" // resolved link should not go out of the base link
|
||||
// hint: With Markdown v2.5.2, there is a new syntax: [link](URL){:target="_blank"} , but we do not support it now
|
||||
|
||||
render(
|
||||
"",
|
||||
`<p><a href="`+result+`" target="_blank" rel="nofollow noopener"><img src="`+result+`" alt="`+title+`"/></a></p>`)
|
||||
|
||||
render(
|
||||
"[["+title+"|"+url+"]]",
|
||||
`<p><a href="`+result+`" rel="nofollow"><img src="`+result+`" title="`+title+`" alt="`+title+`"/></a></p>`)
|
||||
render(
|
||||
"[]("+href+")",
|
||||
`<p><a href="`+href+`" rel="nofollow"><img src="`+result+`" alt="`+title+`"/></a></p>`)
|
||||
|
||||
render(
|
||||
"",
|
||||
`<p><a href="`+result+`" target="_blank" rel="nofollow noopener"><img src="`+result+`" alt="`+title+`"/></a></p>`)
|
||||
|
||||
@@ -26,67 +26,46 @@ func (it *IssueTemplate) Valid() bool {
|
||||
}
|
||||
|
||||
func TestExtractMetadata(t *testing.T) {
|
||||
t.Run("ValidFrontAndBody", func(t *testing.T) {
|
||||
var meta IssueTemplate
|
||||
body, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest), &meta)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, bodyTest, body)
|
||||
assert.Equal(t, metaTest, meta)
|
||||
assert.True(t, meta.Valid())
|
||||
})
|
||||
for _, mode := range []string{"String", "Bytes"} {
|
||||
t.Run(mode, func(t *testing.T) {
|
||||
extract := func(format string, args ...any) (string, IssueTemplate, error) {
|
||||
var meta IssueTemplate
|
||||
if mode == "String" {
|
||||
body, err := ExtractMetadata(fmt.Sprintf(format, args...), &meta)
|
||||
return body, meta, err
|
||||
} else {
|
||||
body, err := ExtractMetadataBytes(fmt.Appendf(nil, format, args...), &meta)
|
||||
return string(body), meta, err
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("NoFirstSeparator", func(t *testing.T) {
|
||||
var meta IssueTemplate
|
||||
_, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", frontTest, sepTest, bodyTest), &meta)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
t.Run("ValidFrontAndBody", func(t *testing.T) {
|
||||
body, meta, err := extract("%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, bodyTest, body)
|
||||
assert.Equal(t, metaTest, meta)
|
||||
assert.True(t, meta.Valid())
|
||||
})
|
||||
|
||||
t.Run("NoLastSeparator", func(t *testing.T) {
|
||||
var meta IssueTemplate
|
||||
_, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, bodyTest), &meta)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
t.Run("NoFirstSeparator", func(t *testing.T) {
|
||||
_, _, err := extract("%s\n%s\n%s", frontTest, sepTest, bodyTest)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("NoBody", func(t *testing.T) {
|
||||
var meta IssueTemplate
|
||||
body, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, sepTest), &meta)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, body)
|
||||
assert.Equal(t, metaTest, meta)
|
||||
assert.True(t, meta.Valid())
|
||||
})
|
||||
}
|
||||
t.Run("NoLastSeparator", func(t *testing.T) {
|
||||
_, _, err := extract("%s\n%s\n%s", sepTest, frontTest, bodyTest)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
func TestExtractMetadataBytes(t *testing.T) {
|
||||
t.Run("ValidFrontAndBody", func(t *testing.T) {
|
||||
var meta IssueTemplate
|
||||
body, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest), &meta)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, bodyTest, string(body))
|
||||
assert.Equal(t, metaTest, meta)
|
||||
assert.True(t, meta.Valid())
|
||||
})
|
||||
|
||||
t.Run("NoFirstSeparator", func(t *testing.T) {
|
||||
var meta IssueTemplate
|
||||
_, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s", frontTest, sepTest, bodyTest), &meta)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("NoLastSeparator", func(t *testing.T) {
|
||||
var meta IssueTemplate
|
||||
_, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s", sepTest, frontTest, bodyTest), &meta)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("NoBody", func(t *testing.T) {
|
||||
var meta IssueTemplate
|
||||
body, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s", sepTest, frontTest, sepTest), &meta)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, string(body))
|
||||
assert.Equal(t, metaTest, meta)
|
||||
assert.True(t, meta.Valid())
|
||||
})
|
||||
t.Run("NoBody", func(t *testing.T) {
|
||||
body, meta, err := extract("%s\n%s\n%s", sepTest, frontTest, sepTest)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, body)
|
||||
assert.Equal(t, metaTest, meta)
|
||||
assert.True(t, meta.Valid())
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -12,17 +12,12 @@ import (
|
||||
)
|
||||
|
||||
func TestRenderIFrame(t *testing.T) {
|
||||
render := func(ctx *RenderContext, opts ExternalRendererOptions) string {
|
||||
sb := &strings.Builder{}
|
||||
require.NoError(t, RenderIFrame(ctx, &opts, sb))
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
ctx := NewRenderContext(t.Context()).
|
||||
WithRelativePath("tree-path").
|
||||
WithMetas(map[string]string{"user": "test-owner", "repo": "test-repo", "RefTypeNameSubURL": "src/branch/master"})
|
||||
|
||||
// iframe doesn't need sandbox, the sandbox is set in render's response header
|
||||
ret := render(ctx, ExternalRendererOptions{ContentSandbox: "any"})
|
||||
assert.Equal(t, `<iframe data-src="/test-owner/test-repo/render/src/branch/master/tree-path" data-global-init="initExternalRenderIframe" class="external-render-iframe"></iframe>`, ret)
|
||||
sb := &strings.Builder{}
|
||||
require.NoError(t, RenderIFrame(ctx, &ExternalRendererOptions{ContentSandbox: "any"}, sb))
|
||||
assert.Equal(t, `<iframe data-src="/test-owner/test-repo/render/src/branch/master/tree-path" data-global-init="initExternalRenderIframe" class="external-render-iframe"></iframe>`, sb.String())
|
||||
}
|
||||
Reference in new issue
Block a user