mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-26 02:00:43 +00:00
875b398e5e
Backport #26745
Fixes #26548
This PR refactors the rendering of markup links. The old code uses
`strings.Replace` to change some urls while the new code uses more
context to decide which link should be generated.
The added tests should ensure the same output for the old and new
behaviour (besides the bug).
We may need to refactor the rendering a bit more to make it clear how
the different helper methods render the input string. There are lots of
options (resolve links / images / mentions / git hashes / emojis / ...)
but you don't really know what helper uses which options. For example,
we currently support images in the user description which should not be
allowed I think:
<details>
<summary>Profile</summary>
https://try.gitea.io/KN4CK3R
![grafik](https://github.com/go-gitea/gitea/assets/1666336/109ae422-496d-4200-b52e-b3a528f553e5)
</details>
(cherry picked from commit 022552d5b6
)
671 lines
25 KiB
Go
671 lines
25 KiB
Go
// Copyright 2017 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package markup_test
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"code.gitea.io/gitea/models/unittest"
|
|
"code.gitea.io/gitea/modules/emoji"
|
|
"code.gitea.io/gitea/modules/git"
|
|
"code.gitea.io/gitea/modules/log"
|
|
. "code.gitea.io/gitea/modules/markup"
|
|
"code.gitea.io/gitea/modules/markup/markdown"
|
|
"code.gitea.io/gitea/modules/setting"
|
|
"code.gitea.io/gitea/modules/util"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
var localMetas = map[string]string{
|
|
"user": "gogits",
|
|
"repo": "gogs",
|
|
"repoPath": "../../tests/gitea-repositories-meta/user13/repo11.git/",
|
|
}
|
|
|
|
func TestMain(m *testing.M) {
|
|
unittest.InitSettings()
|
|
if err := git.InitSimple(context.Background()); err != nil {
|
|
log.Fatal("git init failed, err: %v", err)
|
|
}
|
|
os.Exit(m.Run())
|
|
}
|
|
|
|
func TestRender_Commits(t *testing.T) {
|
|
setting.AppURL = TestAppURL
|
|
test := func(input, expected string) {
|
|
buffer, err := RenderString(&RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
RelativePath: ".md",
|
|
Links: Links{
|
|
Base: TestRepoURL,
|
|
},
|
|
Metas: localMetas,
|
|
}, input)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
|
}
|
|
|
|
sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d"
|
|
repo := TestRepoURL
|
|
commit := util.URLJoin(repo, "commit", sha)
|
|
tree := util.URLJoin(repo, "tree", sha, "src")
|
|
|
|
file := util.URLJoin(repo, "commit", sha, "example.txt")
|
|
fileWithExtra := file + ":"
|
|
fileWithHash := file + "#L2"
|
|
fileWithHasExtra := file + "#L2:"
|
|
commitCompare := util.URLJoin(repo, "compare", sha+"..."+sha)
|
|
commitCompareWithHash := commitCompare + "#L2"
|
|
|
|
test(sha, `<p><a href="`+commit+`" rel="nofollow"><code>65f1bf27bc</code></a></p>`)
|
|
test(sha[:7], `<p><a href="`+commit[:len(commit)-(40-7)]+`" rel="nofollow"><code>65f1bf2</code></a></p>`)
|
|
test(sha[:39], `<p><a href="`+commit[:len(commit)-(40-39)]+`" rel="nofollow"><code>65f1bf27bc</code></a></p>`)
|
|
test(commit, `<p><a href="`+commit+`" rel="nofollow"><code>65f1bf27bc</code></a></p>`)
|
|
test(tree, `<p><a href="`+tree+`" rel="nofollow"><code>65f1bf27bc/src</code></a></p>`)
|
|
|
|
test(file, `<p><a href="`+file+`" rel="nofollow"><code>65f1bf27bc/example.txt</code></a></p>`)
|
|
test(fileWithExtra, `<p><a href="`+file+`" rel="nofollow"><code>65f1bf27bc/example.txt</code></a>:</p>`)
|
|
test(fileWithHash, `<p><a href="`+fileWithHash+`" rel="nofollow"><code>65f1bf27bc/example.txt (L2)</code></a></p>`)
|
|
test(fileWithHasExtra, `<p><a href="`+fileWithHash+`" rel="nofollow"><code>65f1bf27bc/example.txt (L2)</code></a>:</p>`)
|
|
test(commitCompare, `<p><a href="`+commitCompare+`" rel="nofollow"><code>65f1bf27bc...65f1bf27bc</code></a></p>`)
|
|
test(commitCompareWithHash, `<p><a href="`+commitCompareWithHash+`" rel="nofollow"><code>65f1bf27bc...65f1bf27bc (L2)</code></a></p>`)
|
|
|
|
test("commit "+sha, `<p>commit <a href="`+commit+`" rel="nofollow"><code>65f1bf27bc</code></a></p>`)
|
|
test("/home/gitea/"+sha, "<p>/home/gitea/"+sha+"</p>")
|
|
test("deadbeef", `<p>deadbeef</p>`)
|
|
test("d27ace93", `<p>d27ace93</p>`)
|
|
test(sha[:14]+".x", `<p>`+sha[:14]+`.x</p>`)
|
|
|
|
expected14 := `<a href="` + commit[:len(commit)-(40-14)] + `" rel="nofollow"><code>` + sha[:10] + `</code></a>`
|
|
test(sha[:14]+".", `<p>`+expected14+`.</p>`)
|
|
test(sha[:14]+",", `<p>`+expected14+`,</p>`)
|
|
test("["+sha[:14]+"]", `<p>[`+expected14+`]</p>`)
|
|
}
|
|
|
|
func TestRender_CrossReferences(t *testing.T) {
|
|
setting.AppURL = TestAppURL
|
|
|
|
test := func(input, expected string) {
|
|
buffer, err := RenderString(&RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
RelativePath: "a.md",
|
|
Links: Links{
|
|
Base: setting.AppSubURL,
|
|
},
|
|
Metas: localMetas,
|
|
}, input)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
|
}
|
|
|
|
test(
|
|
"gogits/gogs#12345",
|
|
`<p><a href="`+util.URLJoin(TestAppURL, "gogits", "gogs", "issues", "12345")+`" class="ref-issue" rel="nofollow">gogits/gogs#12345</a></p>`)
|
|
test(
|
|
"go-gitea/gitea#12345",
|
|
`<p><a href="`+util.URLJoin(TestAppURL, "go-gitea", "gitea", "issues", "12345")+`" class="ref-issue" rel="nofollow">go-gitea/gitea#12345</a></p>`)
|
|
test(
|
|
"/home/gitea/go-gitea/gitea#12345",
|
|
`<p>/home/gitea/go-gitea/gitea#12345</p>`)
|
|
test(
|
|
util.URLJoin(TestAppURL, "gogitea", "gitea", "issues", "12345"),
|
|
`<p><a href="`+util.URLJoin(TestAppURL, "gogitea", "gitea", "issues", "12345")+`" class="ref-issue" rel="nofollow">gogitea/gitea#12345</a></p>`)
|
|
test(
|
|
util.URLJoin(TestAppURL, "go-gitea", "gitea", "issues", "12345"),
|
|
`<p><a href="`+util.URLJoin(TestAppURL, "go-gitea", "gitea", "issues", "12345")+`" class="ref-issue" rel="nofollow">go-gitea/gitea#12345</a></p>`)
|
|
test(
|
|
util.URLJoin(TestAppURL, "gogitea", "some-repo-name", "issues", "12345"),
|
|
`<p><a href="`+util.URLJoin(TestAppURL, "gogitea", "some-repo-name", "issues", "12345")+`" class="ref-issue" rel="nofollow">gogitea/some-repo-name#12345</a></p>`)
|
|
}
|
|
|
|
func TestMisc_IsSameDomain(t *testing.T) {
|
|
setting.AppURL = TestAppURL
|
|
|
|
sha := "b6dd6210eaebc915fd5be5579c58cce4da2e2579"
|
|
commit := util.URLJoin(TestRepoURL, "commit", sha)
|
|
|
|
assert.True(t, IsSameDomain(commit))
|
|
assert.False(t, IsSameDomain("http://google.com/ncr"))
|
|
assert.False(t, IsSameDomain("favicon.ico"))
|
|
}
|
|
|
|
func TestRender_links(t *testing.T) {
|
|
setting.AppURL = TestAppURL
|
|
|
|
test := func(input, expected string) {
|
|
buffer, err := RenderString(&RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
RelativePath: "a.md",
|
|
Links: Links{
|
|
Base: TestRepoURL,
|
|
},
|
|
}, input)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
|
}
|
|
// Text that should be turned into URL
|
|
|
|
defaultCustom := setting.Markdown.CustomURLSchemes
|
|
setting.Markdown.CustomURLSchemes = []string{"ftp", "magnet"}
|
|
InitializeSanitizer()
|
|
CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes)
|
|
|
|
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 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>`)
|
|
|
|
// Restore previous settings
|
|
setting.Markdown.CustomURLSchemes = defaultCustom
|
|
InitializeSanitizer()
|
|
CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes)
|
|
}
|
|
|
|
func TestRender_email(t *testing.T) {
|
|
setting.AppURL = TestAppURL
|
|
|
|
test := func(input, expected string) {
|
|
res, err := RenderString(&RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
RelativePath: "a.md",
|
|
Links: Links{
|
|
Base: TestRepoURL,
|
|
},
|
|
}, input)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res))
|
|
}
|
|
// 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!`,
|
|
`<p><a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>,<br/>
|
|
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>.<br/>
|
|
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>;<br/>
|
|
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>?<br/>
|
|
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>!</p>`)
|
|
|
|
// Test that should *not* be turned into email links
|
|
test(
|
|
"\"info@gitea.com\"",
|
|
`<p>"info@gitea.com"</p>`)
|
|
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(
|
|
"gitea@3",
|
|
`<p>gitea@3</p>`)
|
|
test(
|
|
"gitea@gmail.c",
|
|
`<p>gitea@gmail.c</p>`)
|
|
test(
|
|
"email@domain@domain.com",
|
|
`<p>email@domain@domain.com</p>`)
|
|
test(
|
|
"email@domain..com",
|
|
`<p>email@domain..com</p>`)
|
|
}
|
|
|
|
func TestRender_emoji(t *testing.T) {
|
|
setting.AppURL = TestAppURL
|
|
setting.StaticURLPrefix = TestAppURL
|
|
|
|
test := func(input, expected string) {
|
|
expected = strings.ReplaceAll(expected, "&", "&")
|
|
buffer, err := RenderString(&RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
RelativePath: "a.md",
|
|
Links: Links{
|
|
Base: TestRepoURL,
|
|
},
|
|
}, input)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
|
}
|
|
|
|
// Make sure we can successfully match every emoji in our dataset with regex
|
|
for i := range emoji.GemojiData {
|
|
test(
|
|
emoji.GemojiData[i].Emoji,
|
|
`<p><span class="emoji" aria-label="`+emoji.GemojiData[i].Description+`">`+emoji.GemojiData[i].Emoji+`</span></p>`)
|
|
}
|
|
for i := range emoji.GemojiData {
|
|
test(
|
|
":"+emoji.GemojiData[i].Aliases[0]+":",
|
|
`<p><span class="emoji" aria-label="`+emoji.GemojiData[i].Description+`">`+emoji.GemojiData[i].Emoji+`</span></p>`)
|
|
}
|
|
|
|
// Text that should be turned into or recognized as emoji
|
|
test(
|
|
":gitea:",
|
|
`<p><span class="emoji" aria-label="gitea"><img alt=":gitea:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/gitea.png"/></span></p>`)
|
|
test(
|
|
":custom-emoji:",
|
|
`<p>:custom-emoji:</p>`)
|
|
setting.UI.CustomEmojisMap["custom-emoji"] = ":custom-emoji:"
|
|
test(
|
|
":custom-emoji:",
|
|
`<p><span class="emoji" aria-label="custom-emoji"><img alt=":custom-emoji:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/custom-emoji.png"/></span></p>`)
|
|
test(
|
|
"这是字符:1::+1: some🐊 \U0001f44d:custom-emoji: :gitea:",
|
|
`<p>这是字符:1:<span class="emoji" aria-label="thumbs up">👍</span> some<span class="emoji" aria-label="crocodile">🐊</span> `+
|
|
`<span class="emoji" aria-label="thumbs up">👍</span><span class="emoji" aria-label="custom-emoji"><img alt=":custom-emoji:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/custom-emoji.png"/></span> `+
|
|
`<span class="emoji" aria-label="gitea"><img alt=":gitea:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/gitea.png"/></span></p>`)
|
|
test(
|
|
"Some text with 😄 in the middle",
|
|
`<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes">😄</span> in the middle</p>`)
|
|
test(
|
|
"Some text with :smile: in the middle",
|
|
`<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes">😄</span> in the middle</p>`)
|
|
test(
|
|
"Some text with 😄😄 2 emoji next to each other",
|
|
`<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes">😄</span><span class="emoji" aria-label="grinning face with smiling eyes">😄</span> 2 emoji next to each other</p>`)
|
|
test(
|
|
"😎🤪🔐🤑❓",
|
|
`<p><span class="emoji" aria-label="smiling face with sunglasses">😎</span><span class="emoji" aria-label="zany face">🤪</span><span class="emoji" aria-label="locked with key">🔐</span><span class="emoji" aria-label="money-mouth face">🤑</span><span class="emoji" aria-label="red question mark">❓</span></p>`)
|
|
|
|
// should match nothing
|
|
test(
|
|
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
|
|
`<p>2001:0db8:85a3:0000:0000:8a2e:0370:7334</p>`)
|
|
test(
|
|
":not exist:",
|
|
`<p>:not exist:</p>`)
|
|
}
|
|
|
|
func TestRender_ShortLinks(t *testing.T) {
|
|
setting.AppURL = TestAppURL
|
|
tree := util.URLJoin(TestRepoURL, "src", "master")
|
|
|
|
test := func(input, expected, expectedWiki string) {
|
|
buffer, err := markdown.RenderString(&RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
Links: Links{
|
|
Base: TestRepoURL,
|
|
BranchPath: "master",
|
|
},
|
|
}, input)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
|
buffer, err = markdown.RenderString(&RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
Links: Links{
|
|
Base: TestRepoURL,
|
|
},
|
|
Metas: localMetas,
|
|
IsWiki: true,
|
|
}, input)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(buffer))
|
|
}
|
|
|
|
mediatree := util.URLJoin(TestRepoURL, "media", "master")
|
|
url := util.URLJoin(tree, "Link")
|
|
otherURL := util.URLJoin(tree, "Other-Link")
|
|
encodedURL := util.URLJoin(tree, "Link%3F")
|
|
imgurl := util.URLJoin(mediatree, "Link.jpg")
|
|
otherImgurl := util.URLJoin(mediatree, "Link+Other.jpg")
|
|
encodedImgurl := util.URLJoin(mediatree, "Link+%23.jpg")
|
|
notencodedImgurl := util.URLJoin(mediatree, "some", "path", "Link+#.jpg")
|
|
urlWiki := util.URLJoin(TestRepoURL, "wiki", "Link")
|
|
otherURLWiki := util.URLJoin(TestRepoURL, "wiki", "Other-Link")
|
|
encodedURLWiki := util.URLJoin(TestRepoURL, "wiki", "Link%3F")
|
|
imgurlWiki := util.URLJoin(TestRepoURL, "wiki", "raw", "Link.jpg")
|
|
otherImgurlWiki := util.URLJoin(TestRepoURL, "wiki", "raw", "Link+Other.jpg")
|
|
encodedImgurlWiki := util.URLJoin(TestRepoURL, "wiki", "raw", "Link+%23.jpg")
|
|
notencodedImgurlWiki := util.URLJoin(TestRepoURL, "wiki", "raw", "some", "path", "Link+#.jpg")
|
|
favicon := "http://google.com/favicon.ico"
|
|
|
|
test(
|
|
"[[Link]]",
|
|
`<p><a href="`+url+`" rel="nofollow">Link</a></p>`,
|
|
`<p><a href="`+urlWiki+`" 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>`,
|
|
`<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" 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>`,
|
|
`<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>`,
|
|
`<p><a href="`+urlWiki+`" rel="nofollow">Name</a></p>`)
|
|
test(
|
|
"[[Name|Link.jpg]]",
|
|
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Name" alt="Name"/></a></p>`,
|
|
`<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" 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>`,
|
|
`<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" 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>`,
|
|
`<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" 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>`,
|
|
`<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" 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>`,
|
|
`<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" 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>`,
|
|
`<p><a href="`+otherImgurlWiki+`" rel="nofollow"><img src="`+otherImgurlWiki+`" 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>`,
|
|
`<p><a href="`+urlWiki+`" rel="nofollow">Link</a> <a href="`+otherURLWiki+`" rel="nofollow">Other Link</a></p>`)
|
|
test(
|
|
"[[Link?]]",
|
|
`<p><a href="`+encodedURL+`" rel="nofollow">Link?</a></p>`,
|
|
`<p><a href="`+encodedURLWiki+`" 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>`,
|
|
`<p><a href="`+urlWiki+`" rel="nofollow">Link</a> <a href="`+otherURLWiki+`" rel="nofollow">Other Link</a> <a href="`+encodedURLWiki+`" rel="nofollow">Link?</a></p>`)
|
|
test(
|
|
"[[Link #.jpg]]",
|
|
`<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`" title="Link #.jpg" alt="Link #.jpg"/></a></p>`,
|
|
`<p><a href="`+encodedImgurlWiki+`" rel="nofollow"><img src="`+encodedImgurlWiki+`" 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>`,
|
|
`<p><a href="`+encodedImgurlWiki+`" rel="nofollow"><img src="`+encodedImgurlWiki+`" title="Title" alt="AltName"/></a></p>`)
|
|
test(
|
|
"[[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="`+notencodedImgurlWiki+`" rel="nofollow"><img src="`+notencodedImgurlWiki+`" 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>`,
|
|
`<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`)
|
|
}
|
|
|
|
func TestRender_RelativeImages(t *testing.T) {
|
|
setting.AppURL = TestAppURL
|
|
|
|
test := func(input, expected, expectedWiki string) {
|
|
buffer, err := markdown.RenderString(&RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
Links: Links{
|
|
Base: TestRepoURL,
|
|
BranchPath: "master",
|
|
},
|
|
Metas: localMetas,
|
|
}, input)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
|
buffer, err = markdown.RenderString(&RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
Links: Links{
|
|
Base: TestRepoURL,
|
|
},
|
|
Metas: localMetas,
|
|
IsWiki: true,
|
|
}, input)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(buffer))
|
|
}
|
|
|
|
rawwiki := util.URLJoin(TestRepoURL, "wiki", "raw")
|
|
mediatree := util.URLJoin(TestRepoURL, "media", "master")
|
|
|
|
test(
|
|
`<img src="Link">`,
|
|
`<img src="`+util.URLJoin(mediatree, "Link")+`"/>`,
|
|
`<img src="`+util.URLJoin(rawwiki, "Link")+`"/>`)
|
|
|
|
test(
|
|
`<img src="./icon.png">`,
|
|
`<img src="`+util.URLJoin(mediatree, "icon.png")+`"/>`,
|
|
`<img src="`+util.URLJoin(rawwiki, "icon.png")+`"/>`)
|
|
}
|
|
|
|
func Test_ParseClusterFuzz(t *testing.T) {
|
|
setting.AppURL = TestAppURL
|
|
|
|
localMetas := map[string]string{
|
|
"user": "go-gitea",
|
|
"repo": "gitea",
|
|
}
|
|
|
|
data := "<A><maTH><tr><MN><bodY ÿ><temPlate></template><tH><tr></A><tH><d<bodY "
|
|
|
|
var res strings.Builder
|
|
err := PostProcess(&RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
Links: Links{
|
|
Base: "https://example.com",
|
|
},
|
|
Metas: localMetas,
|
|
}, strings.NewReader(data), &res)
|
|
assert.NoError(t, err)
|
|
assert.NotContains(t, res.String(), "<html")
|
|
|
|
data = "<!DOCTYPE html>\n<A><maTH><tr><MN><bodY ÿ><temPlate></template><tH><tr></A><tH><d<bodY "
|
|
|
|
res.Reset()
|
|
err = PostProcess(&RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
Links: Links{
|
|
Base: "https://example.com",
|
|
},
|
|
Metas: localMetas,
|
|
}, strings.NewReader(data), &res)
|
|
|
|
assert.NoError(t, err)
|
|
assert.NotContains(t, res.String(), "<html")
|
|
}
|
|
|
|
func TestPostProcess_RenderDocument(t *testing.T) {
|
|
setting.AppURL = TestAppURL
|
|
setting.StaticURLPrefix = TestAppURL // can't run standalone
|
|
|
|
localMetas := map[string]string{
|
|
"user": "go-gitea",
|
|
"repo": "gitea",
|
|
"mode": "document",
|
|
}
|
|
|
|
test := func(input, expected string) {
|
|
var res strings.Builder
|
|
err := PostProcess(&RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
Links: Links{
|
|
Base: "https://example.com",
|
|
},
|
|
Metas: localMetas,
|
|
}, strings.NewReader(input), &res)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res.String()))
|
|
}
|
|
|
|
// Issue index shouldn't be post processing in an document.
|
|
test(
|
|
"#1",
|
|
"#1")
|
|
|
|
// Test that other post processing still works.
|
|
test(
|
|
":gitea:",
|
|
`<span class="emoji" aria-label="gitea"><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" aria-label="grinning face with smiling eyes">😄</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>`)
|
|
}
|
|
|
|
func TestIssue16020(t *testing.T) {
|
|
setting.AppURL = TestAppURL
|
|
|
|
localMetas := map[string]string{
|
|
"user": "go-gitea",
|
|
"repo": "gitea",
|
|
}
|
|
|
|
data := `<img src="data:image/png;base64,i//V"/>`
|
|
|
|
var res strings.Builder
|
|
err := PostProcess(&RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
Metas: localMetas,
|
|
}, strings.NewReader(data), &res)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, data, res.String())
|
|
}
|
|
|
|
func BenchmarkEmojiPostprocess(b *testing.B) {
|
|
data := "🥰 "
|
|
for len(data) < 1<<16 {
|
|
data += data
|
|
}
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
var res strings.Builder
|
|
err := PostProcess(&RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
Metas: localMetas,
|
|
}, strings.NewReader(data), &res)
|
|
assert.NoError(b, err)
|
|
}
|
|
}
|
|
|
|
func TestFuzz(t *testing.T) {
|
|
s := "t/l/issues/8#/../../a"
|
|
renderContext := RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
Links: Links{
|
|
Base: "https://example.com/go-gitea/gitea",
|
|
},
|
|
Metas: map[string]string{
|
|
"user": "go-gitea",
|
|
"repo": "gitea",
|
|
},
|
|
}
|
|
|
|
err := PostProcess(&renderContext, strings.NewReader(s), io.Discard)
|
|
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestIssue18471(t *testing.T) {
|
|
data := `http://domain/org/repo/compare/783b039...da951ce`
|
|
|
|
var res strings.Builder
|
|
err := PostProcess(&RenderContext{
|
|
Ctx: git.DefaultContext,
|
|
Metas: localMetas,
|
|
}, strings.NewReader(data), &res)
|
|
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "<a href=\"http://domain/org/repo/compare/783b039...da951ce\" class=\"compare\"><code class=\"nohighlight\">783b039...da951ce</code></a>", res.String())
|
|
}
|