From e68b9d00a6e05b3a941f63ffb696f91e554ac5ec Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 18 Oct 2024 20:33:49 +0200 Subject: Adding upstream version 9.0.3. Signed-off-by: Daniel Baumann --- modules/markup/html_test.go | 1029 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1029 insertions(+) create mode 100644 modules/markup/html_test.go (limited to 'modules/markup/html_test.go') diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go new file mode 100644 index 0000000..68d1ada --- /dev/null +++ b/modules/markup/html_test.go @@ -0,0 +1,1029 @@ +// 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/test" + "code.gitea.io/gitea/modules/translation" + "code.gitea.io/gitea/modules/util" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +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 = markup.TestAppURL + test := func(input, expected string) { + buffer, err := markup.RenderString(&markup.RenderContext{ + Ctx: git.DefaultContext, + RelativePath: ".md", + Links: markup.Links{ + AbsolutePrefix: true, + Base: markup.TestRepoURL, + }, + Metas: localMetas, + }, input) + require.NoError(t, err) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) + } + + sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d" + repo := markup.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, `

65f1bf27bc

`) + test(sha[:7], `

65f1bf2

`) + test(sha[:39], `

65f1bf27bc

`) + test(commit, `

65f1bf27bc

`) + test(tree, `

65f1bf27bc/src

`) + + test(file, `

65f1bf27bc/example.txt

`) + test(fileWithExtra, `

65f1bf27bc/example.txt:

`) + test(fileWithHash, `

65f1bf27bc/example.txt (L2)

`) + test(fileWithHasExtra, `

65f1bf27bc/example.txt (L2):

`) + test(commitCompare, `

65f1bf27bc...65f1bf27bc

`) + test(commitCompareWithHash, `

65f1bf27bc...65f1bf27bc (L2)

`) + + test("commit "+sha, `

commit 65f1bf27bc

`) + test("/home/gitea/"+sha, "

/home/gitea/"+sha+"

") + test("deadbeef", `

deadbeef

`) + test("d27ace93", `

d27ace93

`) + test(sha[:14]+".x", `

`+sha[:14]+`.x

`) + + expected14 := `` + sha[:10] + `` + test(sha[:14]+".", `

`+expected14+`.

`) + test(sha[:14]+",", `

`+expected14+`,

`) + test("["+sha[:14]+"]", `

[`+expected14+`]

`) +} + +func TestRender_CrossReferences(t *testing.T) { + setting.AppURL = markup.TestAppURL + + test := func(input, expected string) { + buffer, err := markup.RenderString(&markup.RenderContext{ + Ctx: git.DefaultContext, + RelativePath: "a.md", + Links: markup.Links{ + AbsolutePrefix: true, + Base: setting.AppSubURL, + }, + Metas: localMetas, + }, input) + require.NoError(t, err) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) + } + + test( + "gogits/gogs#12345", + `

gogits/gogs#12345

`) + test( + "go-gitea/gitea#12345", + `

go-gitea/gitea#12345

`) + test( + "/home/gitea/go-gitea/gitea#12345", + `

/home/gitea/go-gitea/gitea#12345

`) + test( + util.URLJoin(markup.TestAppURL, "gogitea", "gitea", "issues", "12345"), + `

gogitea/gitea#12345

`) + test( + util.URLJoin(markup.TestAppURL, "go-gitea", "gitea", "issues", "12345"), + `

go-gitea/gitea#12345

`) + test( + util.URLJoin(markup.TestAppURL, "gogitea", "some-repo-name", "issues", "12345"), + `

gogitea/some-repo-name#12345

`) + + sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d" + urlWithQuery := util.URLJoin(markup.TestAppURL, "forgejo", "some-repo-name", "commit", sha, "README.md") + "?display=source#L1-L5" + test( + urlWithQuery, + `

`+sha[:10]+`/README.md (L1-L5)

`) +} + +func TestRender_links(t *testing.T) { + setting.AppURL = markup.TestAppURL + + test := func(input, expected string) { + buffer, err := markup.RenderString(&markup.RenderContext{ + Ctx: git.DefaultContext, + RelativePath: "a.md", + Links: markup.Links{ + Base: markup.TestRepoURL, + }, + }, input) + require.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"} + markup.InitializeSanitizer() + markup.CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes) + + test( + "https://www.example.com", + `

https://www.example.com

`) + test( + "http://www.example.com", + `

http://www.example.com

`) + test( + "https://example.com", + `

https://example.com

`) + test( + "http://example.com", + `

http://example.com

`) + test( + "http://foo.com/blah_blah", + `

http://foo.com/blah_blah

`) + test( + "http://foo.com/blah_blah/", + `

http://foo.com/blah_blah/

`) + test( + "http://www.example.com/wpstyle/?p=364", + `

http://www.example.com/wpstyle/?p=364

`) + test( + "https://www.example.com/foo/?bar=baz&inga=42&quux", + `

https://www.example.com/foo/?bar=baz&inga=42&quux

`) + test( + "http://142.42.1.1/", + `

http://142.42.1.1/

`) + test( + "https://github.com/go-gitea/gitea/?p=aaa/bbb.html#ccc-ddd", + `

https://github.com/go-gitea/gitea/?p=aaa/bbb.html#ccc-ddd

`) + test( + "https://en.wikipedia.org/wiki/URL_(disambiguation)", + `

https://en.wikipedia.org/wiki/URL_(disambiguation)

`) + test( + "https://foo_bar.example.com/", + `

https://foo_bar.example.com/

`) + test( + "https://stackoverflow.com/questions/2896191/what-is-go-used-fore", + `

https://stackoverflow.com/questions/2896191/what-is-go-used-fore

`) + test( + "https://username:password@gitea.com", + `

https://username:password@gitea.com

`) + test( + "ftp://gitea.com/file.txt", + `

ftp://gitea.com/file.txt

`) + test( + "magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download", + `

magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download

`) + + // Test that should *not* be turned into URL + test( + "www.example.com", + `

www.example.com

`) + test( + "example.com", + `

example.com

`) + test( + "test.example.com", + `

test.example.com

`) + test( + "http://", + `

http://

`) + test( + "https://", + `

https://

`) + test( + "://", + `

://

`) + test( + "www", + `

www

`) + test( + "ftps://gitea.com", + `

ftps://gitea.com

`) + + // Restore previous settings + setting.Markdown.CustomURLSchemes = defaultCustom + markup.InitializeSanitizer() + markup.CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes) +} + +func TestRender_email(t *testing.T) { + setting.AppURL = markup.TestAppURL + + test := func(input, expected string) { + res, err := markup.RenderString(&markup.RenderContext{ + Ctx: git.DefaultContext, + RelativePath: "a.md", + Links: markup.Links{ + Base: markup.TestRepoURL, + }, + }, input) + require.NoError(t, err) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res)) + } + // Text that should be turned into email link + + test( + "info@gitea.com", + `

info@gitea.com

`) + test( + "(info@gitea.com)", + `

(info@gitea.com)

`) + test( + "[info@gitea.com]", + `

[info@gitea.com]

`) + test( + "info@gitea.com.", + `

info@gitea.com.

`) + test( + "firstname+lastname@gitea.com", + `

firstname+lastname@gitea.com

`) + test( + "send email to info@gitea.co.uk.", + `

send email to info@gitea.co.uk.

`) + + 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,
+j.doe@example.com.
+j.doe@example.com;
+j.doe@example.com?
+j.doe@example.com!

`) + + // Test that should *not* be turned into email links + test( + "\"info@gitea.com\"", + `

"info@gitea.com"

`) + test( + "/home/gitea/mailstore/info@gitea/com", + `

/home/gitea/mailstore/info@gitea/com

`) + test( + "git@try.gitea.io:go-gitea/gitea.git", + `

git@try.gitea.io:go-gitea/gitea.git

`) + test( + "gitea@3", + `

gitea@3

`) + test( + "gitea@gmail.c", + `

gitea@gmail.c

`) + test( + "email@domain@domain.com", + `

email@domain@domain.com

`) + test( + "email@domain..com", + `

email@domain..com

`) +} + +func TestRender_emoji(t *testing.T) { + setting.AppURL = markup.TestAppURL + setting.StaticURLPrefix = markup.TestAppURL + + test := func(input, expected string) { + expected = strings.ReplaceAll(expected, "&", "&") + buffer, err := markup.RenderString(&markup.RenderContext{ + Ctx: git.DefaultContext, + RelativePath: "a.md", + Links: markup.Links{ + Base: markup.TestRepoURL, + }, + }, input) + require.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, + `

`+emoji.GemojiData[i].Emoji+`

`) + } + for i := range emoji.GemojiData { + test( + ":"+emoji.GemojiData[i].Aliases[0]+":", + `

`+emoji.GemojiData[i].Emoji+`

`) + } + + // Text that should be turned into or recognized as emoji + test( + ":gitea:", + `

:gitea:

`) + test( + ":custom-emoji:", + `

:custom-emoji:

`) + setting.UI.CustomEmojisMap["custom-emoji"] = ":custom-emoji:" + test( + ":custom-emoji:", + `

:custom-emoji:

`) + test( + "θΏ™ζ˜―ε­—η¬¦:1::+1: some🐊 \U0001f44d:custom-emoji: :gitea:", + `

θΏ™ζ˜―ε­—η¬¦:1:πŸ‘ some🐊 `+ + `πŸ‘:custom-emoji: `+ + `:gitea:

`) + test( + "Some text with πŸ˜„ in the middle", + `

Some text with πŸ˜„ in the middle

`) + test( + "Some text with :smile: in the middle", + `

Some text with πŸ˜„ in the middle

`) + test( + "Some text with πŸ˜„πŸ˜„ 2 emoji next to each other", + `

Some text with πŸ˜„πŸ˜„ 2 emoji next to each other

`) + test( + "😎πŸ€ͺπŸ”πŸ€‘β“", + `

😎πŸ€ͺπŸ”πŸ€‘β“

`) + + // should match nothing + test( + "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + `

2001:0db8:85a3:0000:0000:8a2e:0370:7334

`) + test( + ":not exist:", + `

:not exist:

`) +} + +func TestRender_ShortLinks(t *testing.T) { + setting.AppURL = markup.TestAppURL + tree := util.URLJoin(markup.TestRepoURL, "src", "master") + + test := func(input, expected, expectedWiki string) { + buffer, err := markdown.RenderString(&markup.RenderContext{ + Ctx: git.DefaultContext, + Links: markup.Links{ + Base: markup.TestRepoURL, + BranchPath: "master", + }, + }, input) + require.NoError(t, err) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) + buffer, err = markdown.RenderString(&markup.RenderContext{ + Ctx: git.DefaultContext, + Links: markup.Links{ + Base: markup.TestRepoURL, + }, + Metas: localMetas, + IsWiki: true, + }, input) + require.NoError(t, err) + assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer))) + } + + mediatree := util.URLJoin(markup.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(markup.TestRepoURL, "wiki", "Link") + otherURLWiki := util.URLJoin(markup.TestRepoURL, "wiki", "Other-Link") + encodedURLWiki := util.URLJoin(markup.TestRepoURL, "wiki", "Link%3F") + imgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link.jpg") + otherImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+Other.jpg") + encodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+%23.jpg") + notencodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "some", "path", "Link+#.jpg") + favicon := "http://google.com/favicon.ico" + + test( + "[[Link]]", + `

Link

`, + `

Link

`) + test( + "[[Link.jpg]]", + `

Link.jpg

`, + `

Link.jpg

`) + test( + "[["+favicon+"]]", + `

`+favicon+`

`, + `

`+favicon+`

`) + test( + "[[Name|Link]]", + `

Name

`, + `

Name

`) + test( + "[[Name|Link.jpg]]", + `

Name

`, + `

Name

`) + test( + "[[Name|Link.jpg|alt=AltName]]", + `

AltName

`, + `

AltName

`) + test( + "[[Name|Link.jpg|title=Title]]", + `

Title

`, + `

Title

`) + test( + "[[Name|Link.jpg|alt=AltName|title=Title]]", + `

AltName

`, + `

AltName

`) + test( + "[[Name|Link.jpg|alt=\"AltName\"|title='Title']]", + `

AltName

`, + `

AltName

`) + test( + "[[Name|Link Other.jpg|alt=\"AltName\"|title='Title']]", + `

AltName

`, + `

AltName

`) + test( + "[[Link]] [[Other Link]]", + `

Link Other Link

`, + `

Link Other Link

`) + test( + "[[Link?]]", + `

Link?

`, + `

Link?

`) + test( + "[[Link]] [[Other Link]] [[Link?]]", + `

Link Other Link Link?

`, + `

Link Other Link Link?

`) + test( + "[[Link #.jpg]]", + `

Link #.jpg

`, + `

Link #.jpg

`) + test( + "[[Name|Link #.jpg|alt=\"AltName\"|title='Title']]", + `

AltName

`, + `

AltName

`) + test( + "[[some/path/Link #.jpg]]", + `

some/path/Link #.jpg

`, + `

some/path/Link #.jpg

`) + test( + "

[[foobar]]

", + `

[[foobar]]

`, + `

[[foobar]]

`) +} + +func TestRender_RelativeImages(t *testing.T) { + setting.AppURL = markup.TestAppURL + + test := func(input, expected, expectedWiki string) { + buffer, err := markdown.RenderString(&markup.RenderContext{ + Ctx: git.DefaultContext, + Links: markup.Links{ + Base: markup.TestRepoURL, + BranchPath: "master", + }, + Metas: localMetas, + }, input) + require.NoError(t, err) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) + buffer, err = markdown.RenderString(&markup.RenderContext{ + Ctx: git.DefaultContext, + Links: markup.Links{ + Base: markup.TestRepoURL, + }, + Metas: localMetas, + IsWiki: true, + }, input) + require.NoError(t, err) + assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer))) + } + + rawwiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw") + mediatree := util.URLJoin(markup.TestRepoURL, "media", "master") + + test( + ``, + ``, + ``) + + test( + ``, + ``, + ``) +} + +func Test_ParseClusterFuzz(t *testing.T) { + setting.AppURL = markup.TestAppURL + + localMetas := map[string]string{ + "user": "go-gitea", + "repo": "gitea", + } + + data := "
go-gitea/gitea#12345`) + + // Test that other post processing still works. + test( + ":gitea:", + `:gitea:`) + test( + "Some text with πŸ˜„ in the middle", + `Some text with πŸ˜„ in the middle`) + test("http://localhost:3000/person/repo/issues/4#issuecomment-1234", + `person/repo#4 (comment)`) +} + +func TestIssue16020(t *testing.T) { + setting.AppURL = markup.TestAppURL + + localMetas := map[string]string{ + "user": "go-gitea", + "repo": "gitea", + } + + data := `` + + var res strings.Builder + err := markup.PostProcess(&markup.RenderContext{ + Ctx: git.DefaultContext, + Metas: localMetas, + }, strings.NewReader(data), &res) + require.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 := markup.PostProcess(&markup.RenderContext{ + Ctx: git.DefaultContext, + Metas: localMetas, + }, strings.NewReader(data), &res) + require.NoError(b, err) + } +} + +func TestFuzz(t *testing.T) { + s := "t/l/issues/8#/../../a" + renderContext := markup.RenderContext{ + Ctx: git.DefaultContext, + Links: markup.Links{ + Base: "https://example.com/go-gitea/gitea", + }, + Metas: map[string]string{ + "user": "go-gitea", + "repo": "gitea", + }, + } + + err := markup.PostProcess(&renderContext, strings.NewReader(s), io.Discard) + + require.NoError(t, err) +} + +func TestIssue18471(t *testing.T) { + data := `http://domain/org/repo/compare/783b039...da951ce` + + var res strings.Builder + err := markup.PostProcess(&markup.RenderContext{ + Ctx: git.DefaultContext, + Metas: localMetas, + }, strings.NewReader(data), &res) + + require.NoError(t, err) + assert.Equal(t, "783b039...da951ce", res.String()) +} + +func TestRender_FilePreview(t *testing.T) { + defer test.MockVariableValue(&setting.StaticRootPath, "../../")() + defer test.MockVariableValue(&setting.Names, []string{"english"})() + defer test.MockVariableValue(&setting.Langs, []string{"en-US"})() + translation.InitLocales(context.Background()) + + setting.AppURL = markup.TestAppURL + markup.Init(&markup.ProcessorHelper{ + GetRepoFileBlob: func(ctx context.Context, ownerName, repoName, commitSha, filePath string, language *string) (*git.Blob, error) { + gitRepo, err := git.OpenRepository(git.DefaultContext, "./tests/repo/repo1_filepreview") + require.NoError(t, err) + defer gitRepo.Close() + + commit, err := gitRepo.GetCommit(commitSha) + require.NoError(t, err) + + blob, err := commit.GetBlobByPath(filePath) + require.NoError(t, err) + + return blob, nil + }, + }) + + sha := "190d9492934af498c3f669d6a2431dc5459e5b20" + commitFilePreview := util.URLJoin(markup.TestRepoURL, "src", "commit", sha, "path", "to", "file.go") + "#L2-L3" + + testRender := func(input, expected string, metas map[string]string) { + buffer, err := markup.RenderString(&markup.RenderContext{ + Ctx: git.DefaultContext, + RelativePath: ".md", + Metas: metas, + }, input) + require.NoError(t, err) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) + } + + t.Run("single", func(t *testing.T) { + testRender( + commitFilePreview, + `

`+ + `
`+ + `
`+ + `
`+ + `path/to/file.go`+ + `
`+ + ``+ + `Lines 2 to 3 in 190d949`+ + ``+ + `
`+ + `
`+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + `
B`+"\n"+`
C`+"\n"+`
`+ + `
`+ + `
`+ + `

`, + localMetas, + ) + }) + + t.Run("cross-repo", func(t *testing.T) { + testRender( + commitFilePreview, + `

`+ + `
`+ + `
`+ + `
`+ + `gogits/gogs – `+ + `path/to/file.go`+ + `
`+ + ``+ + `Lines 2 to 3 in gogits/gogs@190d949`+ + ``+ + `
`+ + `
`+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + `
B`+"\n"+`
C`+"\n"+`
`+ + `
`+ + `
`+ + `

`, + map[string]string{ + "user": "gogits", + "repo": "gogs2", + }, + ) + }) + t.Run("single-line", func(t *testing.T) { + testRender( + util.URLJoin(markup.TestRepoURL, "src", "commit", "4c1aaf56bcb9f39dcf65f3f250726850aed13cd6", "single-line.txt")+"#L1", + `

`+ + `
`+ + `
`+ + `
`+ + `gogits/gogs – `+ + `single-line.txt`+ + `
`+ + ``+ + `Line 1 in gogits/gogs@4c1aaf5`+ + ``+ + `
`+ + `
`+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + `
A`+`
`+ + `
`+ + `
`+ + `

`, + map[string]string{ + "user": "gogits", + "repo": "gogs2", + }, + ) + }) + + t.Run("AppSubURL", func(t *testing.T) { + urlWithSub := util.URLJoin(markup.TestAppURL, "sub", markup.TestOrgRepo, "src", "commit", sha, "path", "to", "file.go") + "#L2-L3" + + testRender( + urlWithSub, + `

190d949293/path/to/file.go (L2-L3)

`, + localMetas, + ) + + defer test.MockVariableValue(&setting.AppURL, markup.TestAppURL+"sub/")() + defer test.MockVariableValue(&setting.AppSubURL, "/sub")() + + testRender( + urlWithSub, + `

`+ + `
`+ + `
`+ + `
`+ + `path/to/file.go`+ + `
`+ + ``+ + `Lines 2 to 3 in 190d949`+ + ``+ + `
`+ + `
`+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + `
B`+"\n"+`
C`+"\n"+`
`+ + `
`+ + `
`+ + `

`, + localMetas, + ) + + testRender( + "first without sub "+commitFilePreview+" second "+urlWithSub, + `

first without sub 190d949293/path/to/file.go (L2-L3) second

`+ + `
`+ + `
`+ + `
`+ + `path/to/file.go`+ + `
`+ + ``+ + `Lines 2 to 3 in 190d949`+ + ``+ + `
`+ + `
`+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + `
B`+"\n"+`
C`+"\n"+`
`+ + `
`+ + `
`+ + `

`, + localMetas, + ) + }) + + t.Run("multiples", func(t *testing.T) { + testRender( + "first "+commitFilePreview+" second "+commitFilePreview, + `

first

`+ + `
`+ + `
`+ + `
`+ + `path/to/file.go`+ + `
`+ + ``+ + `Lines 2 to 3 in 190d949`+ + ``+ + `
`+ + `
`+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + `
B`+"\n"+`
C`+"\n"+`
`+ + `
`+ + `
`+ + `

second

`+ + `
`+ + `
`+ + `
`+ + `path/to/file.go`+ + `
`+ + ``+ + `Lines 2 to 3 in 190d949`+ + ``+ + `
`+ + `
`+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + `
B`+"\n"+`
C`+"\n"+`
`+ + `
`+ + `
`+ + `

`, + localMetas, + ) + + testRender( + "first "+commitFilePreview+" second "+commitFilePreview+" third "+commitFilePreview, + `

first

`+ + `
`+ + `
`+ + `
`+ + `path/to/file.go`+ + `
`+ + ``+ + `Lines 2 to 3 in 190d949`+ + ``+ + `
`+ + `
`+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + `
B`+"\n"+`
C`+"\n"+`
`+ + `
`+ + `
`+ + `

second

`+ + `
`+ + `
`+ + `
`+ + `path/to/file.go`+ + `
`+ + ``+ + `Lines 2 to 3 in 190d949`+ + ``+ + `
`+ + `
`+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + `
B`+"\n"+`
C`+"\n"+`
`+ + `
`+ + `
`+ + `

third

`+ + `
`+ + `
`+ + `
`+ + `path/to/file.go`+ + `
`+ + ``+ + `Lines 2 to 3 in 190d949`+ + ``+ + `
`+ + `
`+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + ``+ + `
B`+"\n"+`
C`+"\n"+`
`+ + `
`+ + `
`+ + `

`, + localMetas, + ) + }) +} -- cgit v1.2.3