loading up the forgejo repo on tangled to test page performance
at forgejo 1164 lines 45 kB view raw
1// Copyright 2017 The Gitea Authors. All rights reserved. 2// Copyright 2025 The Forgejo Authors. 3// SPDX-License-Identifier: MIT 4 5package markup_test 6 7import ( 8 "context" 9 "io" 10 "os" 11 "strings" 12 "testing" 13 14 "forgejo.org/models/unittest" 15 "forgejo.org/modules/emoji" 16 "forgejo.org/modules/git" 17 "forgejo.org/modules/log" 18 "forgejo.org/modules/markup" 19 "forgejo.org/modules/markup/markdown" 20 "forgejo.org/modules/setting" 21 "forgejo.org/modules/test" 22 "forgejo.org/modules/translation" 23 "forgejo.org/modules/util" 24 25 "github.com/stretchr/testify/assert" 26 "github.com/stretchr/testify/require" 27) 28 29var localMetas = map[string]string{ 30 "user": "gogits", 31 "repo": "gogs", 32 "repoPath": "../../tests/gitea-repositories-meta/user13/repo11.git/", 33} 34 35func TestMain(m *testing.M) { 36 unittest.InitSettings() 37 if err := git.InitSimple(context.Background()); err != nil { 38 log.Fatal("git init failed, err: %v", err) 39 } 40 os.Exit(m.Run()) 41} 42 43func TestRender_Commits(t *testing.T) { 44 setting.AppURL = markup.TestAppURL 45 test := func(input, expected string) { 46 buffer, err := markup.RenderString(&markup.RenderContext{ 47 Ctx: git.DefaultContext, 48 RelativePath: ".md", 49 Links: markup.Links{ 50 AbsolutePrefix: true, 51 Base: markup.TestRepoURL, 52 }, 53 Metas: localMetas, 54 }, input) 55 require.NoError(t, err) 56 assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) 57 } 58 59 sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d" 60 repo := markup.TestRepoURL 61 commit := util.URLJoin(repo, "commit", sha) 62 tree := util.URLJoin(repo, "tree", sha, "src") 63 64 file := util.URLJoin(repo, "commit", sha, "example.txt") 65 fileWithExtra := file + ":" 66 fileWithHash := file + "#L2" 67 fileWithHasExtra := file + "#L2:" 68 commitCompare := util.URLJoin(repo, "compare", sha+"..."+sha) 69 commitCompareWithHash := commitCompare + "#L2" 70 71 test(sha, `<p><a href="`+commit+`" rel="nofollow"><code>65f1bf27bc</code></a></p>`) 72 test(sha[:7], `<p><a href="`+commit[:len(commit)-(40-7)]+`" rel="nofollow"><code>65f1bf2</code></a></p>`) 73 test(sha[:39], `<p><a href="`+commit[:len(commit)-(40-39)]+`" rel="nofollow"><code>65f1bf27bc</code></a></p>`) 74 test(commit, `<p><a href="`+commit+`" rel="nofollow"><code>65f1bf27bc</code></a></p>`) 75 test(tree, `<p><a href="`+tree+`" rel="nofollow"><code>65f1bf27bc/src</code></a></p>`) 76 77 test(file, `<p><a href="`+file+`" rel="nofollow"><code>65f1bf27bc/example.txt</code></a></p>`) 78 test(fileWithExtra, `<p><a href="`+file+`" rel="nofollow"><code>65f1bf27bc/example.txt</code></a>:</p>`) 79 test(fileWithHash, `<p><a href="`+fileWithHash+`" rel="nofollow"><code>65f1bf27bc/example.txt (L2)</code></a></p>`) 80 test(fileWithHasExtra, `<p><a href="`+fileWithHash+`" rel="nofollow"><code>65f1bf27bc/example.txt (L2)</code></a>:</p>`) 81 test(commitCompare, `<p><a href="`+commitCompare+`" rel="nofollow"><code>65f1bf27bc...65f1bf27bc</code></a></p>`) 82 test(commitCompareWithHash, `<p><a href="`+commitCompareWithHash+`" rel="nofollow"><code>65f1bf27bc...65f1bf27bc (L2)</code></a></p>`) 83 84 test("commit "+sha, `<p>commit <a href="`+commit+`" rel="nofollow"><code>65f1bf27bc</code></a></p>`) 85 test("/home/gitea/"+sha, "<p>/home/gitea/"+sha+"</p>") 86 test("deadbeef", `<p>deadbeef</p>`) 87 test("d27ace93", `<p>d27ace93</p>`) 88 test(sha[:14]+".x", `<p>`+sha[:14]+`.x</p>`) 89 90 expected14 := `<a href="` + commit[:len(commit)-(40-14)] + `" rel="nofollow"><code>` + sha[:10] + `</code></a>` 91 test(sha[:14]+".", `<p>`+expected14+`.</p>`) 92 test(sha[:14]+",", `<p>`+expected14+`,</p>`) 93 test("["+sha[:14]+"]", `<p>[`+expected14+`]</p>`) 94} 95 96func TestRender_CrossReferences(t *testing.T) { 97 setting.AppURL = markup.TestAppURL 98 99 test := func(input, expected string) { 100 buffer, err := markup.RenderString(&markup.RenderContext{ 101 Ctx: git.DefaultContext, 102 RelativePath: "a.md", 103 Links: markup.Links{ 104 AbsolutePrefix: true, 105 Base: setting.AppSubURL, 106 }, 107 Metas: localMetas, 108 }, input) 109 require.NoError(t, err) 110 assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) 111 } 112 113 test( 114 "gogits/gogs#12345", 115 `<p><a href="`+util.URLJoin(markup.TestAppURL, "gogits", "gogs", "issues", "12345")+`" class="ref-issue" rel="nofollow">gogits/gogs#12345</a></p>`) 116 test( 117 "go-gitea/gitea#12345", 118 `<p><a href="`+util.URLJoin(markup.TestAppURL, "go-gitea", "gitea", "issues", "12345")+`" class="ref-issue" rel="nofollow">go-gitea/gitea#12345</a></p>`) 119 test( 120 "/home/gitea/go-gitea/gitea#12345", 121 `<p>/home/gitea/go-gitea/gitea#12345</p>`) 122 test( 123 util.URLJoin(markup.TestAppURL, "gogitea", "gitea", "issues", "12345"), 124 `<p><a href="`+util.URLJoin(markup.TestAppURL, "gogitea", "gitea", "issues", "12345")+`" class="ref-issue" rel="nofollow">gogitea/gitea#12345</a></p>`) 125 test( 126 util.URLJoin(markup.TestAppURL, "go-gitea", "gitea", "issues", "12345"), 127 `<p><a href="`+util.URLJoin(markup.TestAppURL, "go-gitea", "gitea", "issues", "12345")+`" class="ref-issue" rel="nofollow">go-gitea/gitea#12345</a></p>`) 128 test( 129 util.URLJoin(markup.TestAppURL, "gogitea", "some-repo-name", "issues", "12345"), 130 `<p><a href="`+util.URLJoin(markup.TestAppURL, "gogitea", "some-repo-name", "issues", "12345")+`" class="ref-issue" rel="nofollow">gogitea/some-repo-name#12345</a></p>`) 131 132 sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d" 133 urlWithQuery := util.URLJoin(markup.TestAppURL, "forgejo", "some-repo-name", "commit", sha, "README.md") + "?display=source#L1-L5" 134 test( 135 urlWithQuery, 136 `<p><a href="`+urlWithQuery+`" rel="nofollow"><code>`+sha[:10]+`/README.md (L1-L5)</code></a></p>`) 137} 138 139func TestRender_links(t *testing.T) { 140 setting.AppURL = markup.TestAppURL 141 142 test := func(input, expected string) { 143 buffer, err := markup.RenderString(&markup.RenderContext{ 144 Ctx: git.DefaultContext, 145 RelativePath: "a.md", 146 Links: markup.Links{ 147 Base: markup.TestRepoURL, 148 }, 149 }, input) 150 require.NoError(t, err) 151 assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) 152 } 153 // Text that should be turned into URL 154 155 defaultCustom := setting.Markdown.CustomURLSchemes 156 setting.Markdown.CustomURLSchemes = []string{"ftp", "magnet"} 157 markup.InitializeSanitizer() 158 markup.CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes) 159 160 test( 161 "https://www.example.com", 162 `<p><a href="https://www.example.com" rel="nofollow">https://www.example.com</a></p>`) 163 test( 164 "http://www.example.com", 165 `<p><a href="http://www.example.com" rel="nofollow">http://www.example.com</a></p>`) 166 test( 167 "https://example.com", 168 `<p><a href="https://example.com" rel="nofollow">https://example.com</a></p>`) 169 test( 170 "http://example.com", 171 `<p><a href="http://example.com" rel="nofollow">http://example.com</a></p>`) 172 test( 173 "http://foo.com/blah_blah", 174 `<p><a href="http://foo.com/blah_blah" rel="nofollow">http://foo.com/blah_blah</a></p>`) 175 test( 176 "http://foo.com/blah_blah/", 177 `<p><a href="http://foo.com/blah_blah/" rel="nofollow">http://foo.com/blah_blah/</a></p>`) 178 test( 179 "http://www.example.com/wpstyle/?p=364", 180 `<p><a href="http://www.example.com/wpstyle/?p=364" rel="nofollow">http://www.example.com/wpstyle/?p=364</a></p>`) 181 test( 182 "https://www.example.com/foo/?bar=baz&inga=42&quux", 183 `<p><a href="https://www.example.com/foo/?bar=baz&amp;inga=42&amp;quux" rel="nofollow">https://www.example.com/foo/?bar=baz&amp;inga=42&amp;quux</a></p>`) 184 test( 185 "http://142.42.1.1/", 186 `<p><a href="http://142.42.1.1/" rel="nofollow">http://142.42.1.1/</a></p>`) 187 test( 188 "https://github.com/go-gitea/gitea/?p=aaa/bbb.html#ccc-ddd", 189 `<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>`) 190 test( 191 "https://en.wikipedia.org/wiki/URL_(disambiguation)", 192 `<p><a href="https://en.wikipedia.org/wiki/URL_(disambiguation)" rel="nofollow">https://en.wikipedia.org/wiki/URL_(disambiguation)</a></p>`) 193 test( 194 "https://foo_bar.example.com/", 195 `<p><a href="https://foo_bar.example.com/" rel="nofollow">https://foo_bar.example.com/</a></p>`) 196 test( 197 "https://stackoverflow.com/questions/2896191/what-is-go-used-fore", 198 `<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>`) 199 test( 200 "https://username:password@gitea.com", 201 `<p><a href="https://username:password@gitea.com" rel="nofollow">https://username:password@gitea.com</a></p>`) 202 test( 203 "ftp://gitea.com/file.txt", 204 `<p><a href="ftp://gitea.com/file.txt" rel="nofollow">ftp://gitea.com/file.txt</a></p>`) 205 test( 206 "magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download", 207 `<p><a href="magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&amp;dn=download" rel="nofollow">magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&amp;dn=download</a></p>`) 208 209 // Test that should *not* be turned into URL 210 test( 211 "www.example.com", 212 `<p>www.example.com</p>`) 213 test( 214 "example.com", 215 `<p>example.com</p>`) 216 test( 217 "test.example.com", 218 `<p>test.example.com</p>`) 219 test( 220 "http://", 221 `<p>http://</p>`) 222 test( 223 "https://", 224 `<p>https://</p>`) 225 test( 226 "://", 227 `<p>://</p>`) 228 test( 229 "www", 230 `<p>www</p>`) 231 test( 232 "ftps://gitea.com", 233 `<p>ftps://gitea.com</p>`) 234 235 // Restore previous settings 236 setting.Markdown.CustomURLSchemes = defaultCustom 237 markup.InitializeSanitizer() 238 markup.CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes) 239} 240 241func TestRender_email(t *testing.T) { 242 setting.AppURL = markup.TestAppURL 243 244 test := func(input, expected string) { 245 res, err := markup.RenderString(&markup.RenderContext{ 246 Ctx: git.DefaultContext, 247 RelativePath: "a.md", 248 Links: markup.Links{ 249 Base: markup.TestRepoURL, 250 }, 251 }, input) 252 require.NoError(t, err) 253 assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res)) 254 } 255 // Text that should be turned into email link 256 257 test( 258 "info@gitea.com", 259 `<p><a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a></p>`) 260 test( 261 "(info@gitea.com)", 262 `<p>(<a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>)</p>`) 263 test( 264 "[info@gitea.com]", 265 `<p>[<a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>]</p>`) 266 test( 267 "info@gitea.com.", 268 `<p><a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>.</p>`) 269 test( 270 "firstname+lastname@gitea.com", 271 `<p><a href="mailto:firstname+lastname@gitea.com" rel="nofollow">firstname+lastname@gitea.com</a></p>`) 272 test( 273 "send email to info@gitea.co.uk.", 274 `<p>send email to <a href="mailto:info@gitea.co.uk" rel="nofollow">info@gitea.co.uk</a>.</p>`) 275 276 test( 277 `j.doe@example.com, 278 j.doe@example.com. 279 j.doe@example.com; 280 j.doe@example.com? 281 j.doe@example.com!`, 282 `<p><a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>,<br/> 283<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>.<br/> 284<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>;<br/> 285<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>?<br/> 286<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>!</p>`) 287 288 // Test that should *not* be turned into email links 289 test( 290 "\"info@gitea.com\"", 291 `<p>&#34;info@gitea.com&#34;</p>`) 292 test( 293 "/home/gitea/mailstore/info@gitea/com", 294 `<p>/home/gitea/mailstore/info@gitea/com</p>`) 295 test( 296 "git@try.gitea.io:go-gitea/gitea.git", 297 `<p>git@try.gitea.io:go-gitea/gitea.git</p>`) 298 test( 299 "gitea@3", 300 `<p>gitea@3</p>`) 301 test( 302 "gitea@gmail.c", 303 `<p>gitea@gmail.c</p>`) 304 test( 305 "email@domain@domain.com", 306 `<p>email@domain@domain.com</p>`) 307 test( 308 "email@domain..com", 309 `<p>email@domain..com</p>`) 310} 311 312func TestRender_emoji(t *testing.T) { 313 setting.AppURL = markup.TestAppURL 314 setting.StaticURLPrefix = markup.TestAppURL 315 316 test := func(input, expected string) { 317 expected = strings.ReplaceAll(expected, "&", "&amp;") 318 buffer, err := markup.RenderString(&markup.RenderContext{ 319 Ctx: git.DefaultContext, 320 RelativePath: "a.md", 321 Links: markup.Links{ 322 Base: markup.TestRepoURL, 323 }, 324 }, input) 325 require.NoError(t, err) 326 assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) 327 } 328 329 // Make sure we can successfully match every emoji in our dataset with regex 330 for i := range emoji.GemojiData { 331 test( 332 emoji.GemojiData[i].Emoji, 333 `<p><span class="emoji" aria-label="`+emoji.GemojiData[i].Description+`" data-alias="`+emoji.GemojiData[i].Aliases[0]+`">`+emoji.GemojiData[i].Emoji+`</span></p>`) 334 } 335 for i := range emoji.GemojiData { 336 test( 337 ":"+emoji.GemojiData[i].Aliases[0]+":", 338 `<p><span class="emoji" aria-label="`+emoji.GemojiData[i].Description+`" data-alias="`+emoji.GemojiData[i].Aliases[0]+`">`+emoji.GemojiData[i].Emoji+`</span></p>`) 339 } 340 341 // Text that should be turned into or recognized as emoji 342 test( 343 ":gitea:", 344 `<p><span class="emoji" aria-label="gitea" data-alias="gitea"><img alt=":gitea:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/gitea.png"/></span></p>`) 345 test( 346 ":custom-emoji:", 347 `<p>:custom-emoji:</p>`) 348 setting.UI.CustomEmojisMap["custom-emoji"] = ":custom-emoji:" 349 test( 350 ":custom-emoji:", 351 `<p><span class="emoji" aria-label="custom-emoji" data-alias="custom-emoji"><img alt=":custom-emoji:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/custom-emoji.png"/></span></p>`) 352 test( 353 "这是字符:1::+1: some🐊 \U0001f44d:custom-emoji: :gitea:", 354 `<p>这是字符:1:<span class="emoji" aria-label="thumbs up" data-alias="+1">👍</span> some<span class="emoji" aria-label="crocodile" data-alias="crocodile">🐊</span> `+ 355 `<span class="emoji" aria-label="thumbs up" data-alias="+1">👍</span><span class="emoji" aria-label="custom-emoji" data-alias="custom-emoji"><img alt=":custom-emoji:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/custom-emoji.png"/></span> `+ 356 `<span class="emoji" aria-label="gitea" data-alias="gitea"><img alt=":gitea:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/gitea.png"/></span></p>`) 357 test( 358 "Some text with 😄 in the middle", 359 `<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes" data-alias="smile">😄</span> in the middle</p>`) 360 test( 361 "Some text with :smile: in the middle", 362 `<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes" data-alias="smile">😄</span> in the middle</p>`) 363 test( 364 "Some text with 😄😄 2 emoji next to each other", 365 `<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes" data-alias="smile">😄</span><span class="emoji" aria-label="grinning face with smiling eyes" data-alias="smile">😄</span> 2 emoji next to each other</p>`) 366 test( 367 "😎🤪🔐🤑❓", 368 `<p><span class="emoji" aria-label="smiling face with sunglasses" data-alias="sunglasses">😎</span><span class="emoji" aria-label="zany face" data-alias="zany_face">🤪</span><span class="emoji" aria-label="locked with key" data-alias="closed_lock_with_key">🔐</span><span class="emoji" aria-label="money-mouth face" data-alias="money_mouth_face">🤑</span><span class="emoji" aria-label="red question mark" data-alias="question">❓</span></p>`) 369 370 // should match nothing 371 test( 372 "2001:0db8:85a3:0000:0000:8a2e:0370:7334", 373 `<p>2001:0db8:85a3:0000:0000:8a2e:0370:7334</p>`) 374 test( 375 ":not exist:", 376 `<p>:not exist:</p>`) 377} 378 379func TestRender_ShortLinks(t *testing.T) { 380 setting.AppURL = markup.TestAppURL 381 tree := util.URLJoin(markup.TestRepoURL, "src", "master") 382 383 test := func(input, expected, expectedWiki string) { 384 buffer, err := markdown.RenderString(&markup.RenderContext{ 385 Ctx: git.DefaultContext, 386 Links: markup.Links{ 387 Base: markup.TestRepoURL, 388 BranchPath: "master", 389 }, 390 }, input) 391 require.NoError(t, err) 392 assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) 393 buffer, err = markdown.RenderString(&markup.RenderContext{ 394 Ctx: git.DefaultContext, 395 Links: markup.Links{ 396 Base: markup.TestRepoURL, 397 }, 398 Metas: localMetas, 399 IsWiki: true, 400 }, input) 401 require.NoError(t, err) 402 assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer))) 403 } 404 405 mediatree := util.URLJoin(markup.TestRepoURL, "media", "master") 406 url := util.URLJoin(tree, "Link") 407 otherURL := util.URLJoin(tree, "Other-Link") 408 encodedURL := util.URLJoin(tree, "Link%3F") 409 imgurl := util.URLJoin(mediatree, "Link.jpg") 410 otherImgurl := util.URLJoin(mediatree, "Link+Other.jpg") 411 encodedImgurl := util.URLJoin(mediatree, "Link+%23.jpg") 412 notencodedImgurl := util.URLJoin(mediatree, "some", "path", "Link+#.jpg") 413 urlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "Link") 414 otherURLWiki := util.URLJoin(markup.TestRepoURL, "wiki", "Other-Link") 415 encodedURLWiki := util.URLJoin(markup.TestRepoURL, "wiki", "Link%3F") 416 imgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link.jpg") 417 otherImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+Other.jpg") 418 encodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+%23.jpg") 419 notencodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "some", "path", "Link+#.jpg") 420 favicon := "https://forgejo.org/favicon.ico" 421 422 test( 423 "[[Link]]", 424 `<p><a href="`+url+`" rel="nofollow">Link</a></p>`, 425 `<p><a href="`+urlWiki+`" rel="nofollow">Link</a></p>`) 426 test( 427 "[[Link.jpg]]", 428 `<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Link.jpg" alt=""/></a></p>`, 429 `<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" title="Link.jpg" alt=""/></a></p>`) 430 test( 431 "[["+favicon+"]]", 432 `<p><a href="`+favicon+`" rel="nofollow"><img src="`+favicon+`" title="favicon.ico" alt=""/></a></p>`, 433 `<p><a href="`+favicon+`" rel="nofollow"><img src="`+favicon+`" title="favicon.ico" alt=""/></a></p>`) 434 test( 435 "[[Name|Link]]", 436 `<p><a href="`+url+`" rel="nofollow">Name</a></p>`, 437 `<p><a href="`+urlWiki+`" rel="nofollow">Name</a></p>`) 438 test( 439 "[[Name|Link.jpg]]", 440 `<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Name" alt=""/></a></p>`, 441 `<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" title="Name" alt=""/></a></p>`) 442 test( 443 "[[Name|Link.jpg|alt=AltName]]", 444 `<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="AltName" alt="AltName"/></a></p>`, 445 `<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" title="AltName" alt="AltName"/></a></p>`) 446 test( 447 "[[Name|Link.jpg|title=Title]]", 448 `<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Title" alt=""/></a></p>`, 449 `<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" title="Title" alt=""/></a></p>`) 450 test( 451 "[[Name|Link.jpg|alt=AltName|title=Title]]", 452 `<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Title" alt="AltName"/></a></p>`, 453 `<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" title="Title" alt="AltName"/></a></p>`) 454 test( 455 "[[Name|Link.jpg|alt=\"AltName\"|title='Title']]", 456 `<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Title" alt="AltName"/></a></p>`, 457 `<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" title="Title" alt="AltName"/></a></p>`) 458 test( 459 "[[Name|Link Other.jpg|alt=\"AltName\"|title='Title']]", 460 `<p><a href="`+otherImgurl+`" rel="nofollow"><img src="`+otherImgurl+`" title="Title" alt="AltName"/></a></p>`, 461 `<p><a href="`+otherImgurlWiki+`" rel="nofollow"><img src="`+otherImgurlWiki+`" title="Title" alt="AltName"/></a></p>`) 462 test( 463 "[[Link]] [[Other Link]]", 464 `<p><a href="`+url+`" rel="nofollow">Link</a> <a href="`+otherURL+`" rel="nofollow">Other Link</a></p>`, 465 `<p><a href="`+urlWiki+`" rel="nofollow">Link</a> <a href="`+otherURLWiki+`" rel="nofollow">Other Link</a></p>`) 466 test( 467 "[[Link?]]", 468 `<p><a href="`+encodedURL+`" rel="nofollow">Link?</a></p>`, 469 `<p><a href="`+encodedURLWiki+`" rel="nofollow">Link?</a></p>`) 470 test( 471 "[[Link]] [[Other Link]] [[Link?]]", 472 `<p><a href="`+url+`" rel="nofollow">Link</a> <a href="`+otherURL+`" rel="nofollow">Other Link</a> <a href="`+encodedURL+`" rel="nofollow">Link?</a></p>`, 473 `<p><a href="`+urlWiki+`" rel="nofollow">Link</a> <a href="`+otherURLWiki+`" rel="nofollow">Other Link</a> <a href="`+encodedURLWiki+`" rel="nofollow">Link?</a></p>`) 474 test( 475 "[[Link #.jpg]]", 476 `<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`" title="Link #.jpg" alt=""/></a></p>`, 477 `<p><a href="`+encodedImgurlWiki+`" rel="nofollow"><img src="`+encodedImgurlWiki+`" title="Link #.jpg" alt=""/></a></p>`) 478 test( 479 "[[Name|Link #.jpg|alt=\"AltName\"|title='Title']]", 480 `<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`" title="Title" alt="AltName"/></a></p>`, 481 `<p><a href="`+encodedImgurlWiki+`" rel="nofollow"><img src="`+encodedImgurlWiki+`" title="Title" alt="AltName"/></a></p>`) 482 test( 483 "[[some/path/Link #.jpg]]", 484 `<p><a href="`+notencodedImgurl+`" rel="nofollow"><img src="`+notencodedImgurl+`" title="Link #.jpg" alt=""/></a></p>`, 485 `<p><a href="`+notencodedImgurlWiki+`" rel="nofollow"><img src="`+notencodedImgurlWiki+`" title="Link #.jpg" alt=""/></a></p>`) 486 test( 487 "<p><a href=\"https://example.org\">[[foobar]]</a></p>", 488 `<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`, 489 `<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`) 490} 491 492func TestRender_RelativeImages(t *testing.T) { 493 setting.AppURL = markup.TestAppURL 494 495 test := func(input, expected, expectedWiki string) { 496 buffer, err := markdown.RenderString(&markup.RenderContext{ 497 Ctx: git.DefaultContext, 498 Links: markup.Links{ 499 Base: markup.TestRepoURL, 500 BranchPath: "master", 501 }, 502 Metas: localMetas, 503 }, input) 504 require.NoError(t, err) 505 assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) 506 buffer, err = markdown.RenderString(&markup.RenderContext{ 507 Ctx: git.DefaultContext, 508 Links: markup.Links{ 509 Base: markup.TestRepoURL, 510 }, 511 Metas: localMetas, 512 IsWiki: true, 513 }, input) 514 require.NoError(t, err) 515 assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer))) 516 } 517 518 rawwiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw") 519 mediatree := util.URLJoin(markup.TestRepoURL, "media", "master") 520 521 test( 522 `<img src="Link">`, 523 `<img src="`+util.URLJoin(mediatree, "Link")+`"/>`, 524 `<img src="`+util.URLJoin(rawwiki, "Link")+`"/>`) 525 526 test( 527 `<img src="./icon.png">`, 528 `<img src="`+util.URLJoin(mediatree, "icon.png")+`"/>`, 529 `<img src="`+util.URLJoin(rawwiki, "icon.png")+`"/>`) 530} 531 532func Test_ParseClusterFuzz(t *testing.T) { 533 setting.AppURL = markup.TestAppURL 534 535 localMetas := map[string]string{ 536 "user": "go-gitea", 537 "repo": "gitea", 538 } 539 540 data := "<A><maTH><tr><MN><bodY ÿ><temPlate></template><tH><tr></A><tH><d<bodY " 541 542 var res strings.Builder 543 err := markup.PostProcess(&markup.RenderContext{ 544 Ctx: git.DefaultContext, 545 Links: markup.Links{ 546 Base: "https://example.com", 547 }, 548 Metas: localMetas, 549 }, strings.NewReader(data), &res) 550 require.NoError(t, err) 551 assert.NotContains(t, res.String(), "<html") 552 553 data = "<!DOCTYPE html>\n<A><maTH><tr><MN><bodY ÿ><temPlate></template><tH><tr></A><tH><d<bodY " 554 555 res.Reset() 556 err = markup.PostProcess(&markup.RenderContext{ 557 Ctx: git.DefaultContext, 558 Links: markup.Links{ 559 Base: "https://example.com", 560 }, 561 Metas: localMetas, 562 }, strings.NewReader(data), &res) 563 564 require.NoError(t, err) 565 assert.NotContains(t, res.String(), "<html") 566} 567 568func TestPostProcess_RenderDocument(t *testing.T) { 569 setting.AppURL = markup.TestAppURL 570 setting.StaticURLPrefix = markup.TestAppURL // can't run standalone 571 572 localMetas := map[string]string{ 573 "user": "go-gitea", 574 "repo": "gitea", 575 "mode": "document", 576 } 577 578 test := func(input, expected string) { 579 var res strings.Builder 580 err := markup.PostProcess(&markup.RenderContext{ 581 Ctx: git.DefaultContext, 582 Links: markup.Links{ 583 AbsolutePrefix: true, 584 Base: "https://example.com", 585 }, 586 Metas: localMetas, 587 }, strings.NewReader(input), &res) 588 require.NoError(t, err) 589 assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res.String())) 590 } 591 592 // Issue index shouldn't be post processing in a document. 593 test( 594 "#1", 595 "#1") 596 597 // But cross-referenced issue index should work. 598 test( 599 "go-gitea/gitea#12345", 600 `<a href="`+util.URLJoin(markup.TestAppURL, "go-gitea", "gitea", "issues", "12345")+`" class="ref-issue">go-gitea/gitea#12345</a>`) 601 602 // Test that other post processing still works. 603 test( 604 ":gitea:", 605 `<span class="emoji" aria-label="gitea" data-alias="gitea"><img alt=":gitea:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/gitea.png"/></span>`) 606 test( 607 "Some text with 😄 in the middle", 608 `Some text with <span class="emoji" aria-label="grinning face with smiling eyes" data-alias="smile">😄</span> in the middle`) 609 test("http://localhost:3000/person/repo/issues/4#issuecomment-1234", 610 `<a href="http://localhost:3000/person/repo/issues/4#issuecomment-1234" class="ref-issue">person/repo#4 (comment)</a>`) 611} 612 613func TestIssue16020(t *testing.T) { 614 setting.AppURL = markup.TestAppURL 615 616 localMetas := map[string]string{ 617 "user": "go-gitea", 618 "repo": "gitea", 619 } 620 621 data := `<img src="data:image/png;base64,i//V"/>` 622 623 var res strings.Builder 624 err := markup.PostProcess(&markup.RenderContext{ 625 Ctx: git.DefaultContext, 626 Metas: localMetas, 627 }, strings.NewReader(data), &res) 628 require.NoError(t, err) 629 assert.Equal(t, data, res.String()) 630} 631 632func BenchmarkEmojiPostprocess(b *testing.B) { 633 data := "🥰 " 634 for len(data) < 1<<16 { 635 data += data 636 } 637 b.ResetTimer() 638 for i := 0; i < b.N; i++ { 639 var res strings.Builder 640 err := markup.PostProcess(&markup.RenderContext{ 641 Ctx: git.DefaultContext, 642 Metas: localMetas, 643 }, strings.NewReader(data), &res) 644 require.NoError(b, err) 645 } 646} 647 648func TestFuzz(t *testing.T) { 649 s := "t/l/issues/8#/../../a" 650 renderContext := markup.RenderContext{ 651 Ctx: git.DefaultContext, 652 Links: markup.Links{ 653 Base: "https://example.com/go-gitea/gitea", 654 }, 655 Metas: map[string]string{ 656 "user": "go-gitea", 657 "repo": "gitea", 658 }, 659 } 660 661 err := markup.PostProcess(&renderContext, strings.NewReader(s), io.Discard) 662 663 require.NoError(t, err) 664} 665 666func TestIssue18471(t *testing.T) { 667 data := `http://domain/org/repo/compare/783b039...da951ce` 668 669 var res strings.Builder 670 err := markup.PostProcess(&markup.RenderContext{ 671 Ctx: git.DefaultContext, 672 Metas: localMetas, 673 }, strings.NewReader(data), &res) 674 675 require.NoError(t, err) 676 assert.Equal(t, "<a href=\"http://domain/org/repo/compare/783b039...da951ce\" class=\"compare\"><code class=\"nohighlight\">783b039...da951ce</code></a>", res.String()) 677} 678 679func TestRender_FilePreview(t *testing.T) { 680 defer test.MockVariableValue(&setting.StaticRootPath, "../../")() 681 defer test.MockVariableValue(&setting.Names, []string{"english"})() 682 defer test.MockVariableValue(&setting.Langs, []string{"en-US"})() 683 translation.InitLocales(t.Context()) 684 685 setting.AppURL = markup.TestAppURL 686 markup.Init(&markup.ProcessorHelper{ 687 GetRepoFileBlob: func(ctx context.Context, ownerName, repoName, commitSha, filePath string, language *string) (*git.Blob, error) { 688 gitRepo, err := git.OpenRepository(git.DefaultContext, "./tests/repo/repo1_filepreview") 689 require.NoError(t, err) 690 defer gitRepo.Close() 691 692 commit, err := gitRepo.GetCommit(commitSha) 693 require.NoError(t, err) 694 695 blob, err := commit.GetBlobByPath(filePath) 696 require.NoError(t, err) 697 698 return blob, nil 699 }, 700 }) 701 702 sha := "190d9492934af498c3f669d6a2431dc5459e5b20" 703 commitFilePreview := util.URLJoin(markup.TestRepoURL, "src", "commit", sha, "path", "to", "file.go") + "#L2-L3" 704 705 testRender := func(input, expected string, metas map[string]string) { 706 buffer, err := markup.RenderString(&markup.RenderContext{ 707 Ctx: git.DefaultContext, 708 RelativePath: ".md", 709 Metas: metas, 710 }, input) 711 require.NoError(t, err) 712 assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) 713 } 714 715 t.Run("single", func(t *testing.T) { 716 testRender( 717 commitFilePreview, 718 `<p></p>`+ 719 `<div class="file-preview-box">`+ 720 `<div class="header">`+ 721 `<div>`+ 722 `<a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" class="muted" rel="nofollow">path/to/file.go</a>`+ 723 `</div>`+ 724 `<span class="text grey">`+ 725 `Lines 2 to 3 in <a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20" class="text black" rel="nofollow">190d949</a>`+ 726 `</span>`+ 727 `</div>`+ 728 `<div class="ui table">`+ 729 `<table class="file-preview">`+ 730 `<tbody>`+ 731 `<tr>`+ 732 `<td class="lines-num"><span data-line-number="2"></span></td>`+ 733 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">B</span>`+"\n"+`</code></td>`+ 734 `</tr>`+ 735 `<tr>`+ 736 `<td class="lines-num"><span data-line-number="3"></span></td>`+ 737 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">C</span>`+"\n"+`</code></td>`+ 738 `</tr>`+ 739 `</tbody>`+ 740 `</table>`+ 741 `</div>`+ 742 `</div>`+ 743 `<p></p>`, 744 localMetas, 745 ) 746 }) 747 748 t.Run("cross-repo", func(t *testing.T) { 749 testRender( 750 commitFilePreview, 751 `<p></p>`+ 752 `<div class="file-preview-box">`+ 753 `<div class="header">`+ 754 `<div>`+ 755 `<a href="http://localhost:3000/gogits/gogs/" rel="nofollow">gogits/gogs</a> – `+ 756 `<a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" class="muted" rel="nofollow">path/to/file.go</a>`+ 757 `</div>`+ 758 `<span class="text grey">`+ 759 `Lines 2 to 3 in <a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20" class="text black" rel="nofollow">gogits/gogs@190d949</a>`+ 760 `</span>`+ 761 `</div>`+ 762 `<div class="ui table">`+ 763 `<table class="file-preview">`+ 764 `<tbody>`+ 765 `<tr>`+ 766 `<td class="lines-num"><span data-line-number="2"></span></td>`+ 767 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">B</span>`+"\n"+`</code></td>`+ 768 `</tr>`+ 769 `<tr>`+ 770 `<td class="lines-num"><span data-line-number="3"></span></td>`+ 771 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">C</span>`+"\n"+`</code></td>`+ 772 `</tr>`+ 773 `</tbody>`+ 774 `</table>`+ 775 `</div>`+ 776 `</div>`+ 777 `<p></p>`, 778 map[string]string{ 779 "user": "gogits", 780 "repo": "gogs2", 781 }, 782 ) 783 }) 784 t.Run("single-line", func(t *testing.T) { 785 testRender( 786 util.URLJoin(markup.TestRepoURL, "src", "commit", "4c1aaf56bcb9f39dcf65f3f250726850aed13cd6", "single-line.txt")+"#L1", 787 `<p></p>`+ 788 `<div class="file-preview-box">`+ 789 `<div class="header">`+ 790 `<div>`+ 791 `<a href="http://localhost:3000/gogits/gogs/" rel="nofollow">gogits/gogs</a> – `+ 792 `<a href="http://localhost:3000/gogits/gogs/src/commit/4c1aaf56bcb9f39dcf65f3f250726850aed13cd6/single-line.txt#L1" class="muted" rel="nofollow">single-line.txt</a>`+ 793 `</div>`+ 794 `<span class="text grey">`+ 795 `Line 1 in <a href="http://localhost:3000/gogits/gogs/src/commit/4c1aaf56bcb9f39dcf65f3f250726850aed13cd6" class="text black" rel="nofollow">gogits/gogs@4c1aaf5</a>`+ 796 `</span>`+ 797 `</div>`+ 798 `<div class="ui table">`+ 799 `<table class="file-preview">`+ 800 `<tbody>`+ 801 `<tr>`+ 802 `<td class="lines-num"><span data-line-number="1"></span></td>`+ 803 `<td class="lines-code chroma"><code class="code-inner">A`+`</code></td>`+ 804 `</tr>`+ 805 `</tbody>`+ 806 `</table>`+ 807 `</div>`+ 808 `</div>`+ 809 `<p></p>`, 810 map[string]string{ 811 "user": "gogits", 812 "repo": "gogs2", 813 }, 814 ) 815 }) 816 817 t.Run("AppSubURL", func(t *testing.T) { 818 urlWithSub := util.URLJoin(markup.TestAppURL, "sub", markup.TestOrgRepo, "src", "commit", sha, "path", "to", "file.go") + "#L2-L3" 819 820 testRender( 821 urlWithSub, 822 `<p><a href="http://localhost:3000/sub/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" rel="nofollow"><code>190d949293/path/to/file.go (L2-L3)</code></a></p>`, 823 localMetas, 824 ) 825 826 defer test.MockVariableValue(&setting.AppURL, markup.TestAppURL+"sub/")() 827 defer test.MockVariableValue(&setting.AppSubURL, "/sub")() 828 829 testRender( 830 urlWithSub, 831 `<p></p>`+ 832 `<div class="file-preview-box">`+ 833 `<div class="header">`+ 834 `<div>`+ 835 `<a href="http://localhost:3000/sub/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" class="muted" rel="nofollow">path/to/file.go</a>`+ 836 `</div>`+ 837 `<span class="text grey">`+ 838 `Lines 2 to 3 in <a href="http://localhost:3000/sub/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20" class="text black" rel="nofollow">190d949</a>`+ 839 `</span>`+ 840 `</div>`+ 841 `<div class="ui table">`+ 842 `<table class="file-preview">`+ 843 `<tbody>`+ 844 `<tr>`+ 845 `<td class="lines-num"><span data-line-number="2"></span></td>`+ 846 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">B</span>`+"\n"+`</code></td>`+ 847 `</tr>`+ 848 `<tr>`+ 849 `<td class="lines-num"><span data-line-number="3"></span></td>`+ 850 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">C</span>`+"\n"+`</code></td>`+ 851 `</tr>`+ 852 `</tbody>`+ 853 `</table>`+ 854 `</div>`+ 855 `</div>`+ 856 `<p></p>`, 857 localMetas, 858 ) 859 860 testRender( 861 "first without sub "+commitFilePreview+" second "+urlWithSub, 862 `<p>first without sub <a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" rel="nofollow"><code>190d949293/path/to/file.go (L2-L3)</code></a> second </p>`+ 863 `<div class="file-preview-box">`+ 864 `<div class="header">`+ 865 `<div>`+ 866 `<a href="http://localhost:3000/sub/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" class="muted" rel="nofollow">path/to/file.go</a>`+ 867 `</div>`+ 868 `<span class="text grey">`+ 869 `Lines 2 to 3 in <a href="http://localhost:3000/sub/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20" class="text black" rel="nofollow">190d949</a>`+ 870 `</span>`+ 871 `</div>`+ 872 `<div class="ui table">`+ 873 `<table class="file-preview">`+ 874 `<tbody>`+ 875 `<tr>`+ 876 `<td class="lines-num"><span data-line-number="2"></span></td>`+ 877 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">B</span>`+"\n"+`</code></td>`+ 878 `</tr>`+ 879 `<tr>`+ 880 `<td class="lines-num"><span data-line-number="3"></span></td>`+ 881 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">C</span>`+"\n"+`</code></td>`+ 882 `</tr>`+ 883 `</tbody>`+ 884 `</table>`+ 885 `</div>`+ 886 `</div>`+ 887 `<p></p>`, 888 localMetas, 889 ) 890 }) 891 892 t.Run("multiples", func(t *testing.T) { 893 testRender( 894 "first "+commitFilePreview+" second "+commitFilePreview, 895 `<p>first </p>`+ 896 `<div class="file-preview-box">`+ 897 `<div class="header">`+ 898 `<div>`+ 899 `<a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" class="muted" rel="nofollow">path/to/file.go</a>`+ 900 `</div>`+ 901 `<span class="text grey">`+ 902 `Lines 2 to 3 in <a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20" class="text black" rel="nofollow">190d949</a>`+ 903 `</span>`+ 904 `</div>`+ 905 `<div class="ui table">`+ 906 `<table class="file-preview">`+ 907 `<tbody>`+ 908 `<tr>`+ 909 `<td class="lines-num"><span data-line-number="2"></span></td>`+ 910 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">B</span>`+"\n"+`</code></td>`+ 911 `</tr>`+ 912 `<tr>`+ 913 `<td class="lines-num"><span data-line-number="3"></span></td>`+ 914 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">C</span>`+"\n"+`</code></td>`+ 915 `</tr>`+ 916 `</tbody>`+ 917 `</table>`+ 918 `</div>`+ 919 `</div>`+ 920 `<p> second </p>`+ 921 `<div class="file-preview-box">`+ 922 `<div class="header">`+ 923 `<div>`+ 924 `<a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" class="muted" rel="nofollow">path/to/file.go</a>`+ 925 `</div>`+ 926 `<span class="text grey">`+ 927 `Lines 2 to 3 in <a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20" class="text black" rel="nofollow">190d949</a>`+ 928 `</span>`+ 929 `</div>`+ 930 `<div class="ui table">`+ 931 `<table class="file-preview">`+ 932 `<tbody>`+ 933 `<tr>`+ 934 `<td class="lines-num"><span data-line-number="2"></span></td>`+ 935 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">B</span>`+"\n"+`</code></td>`+ 936 `</tr>`+ 937 `<tr>`+ 938 `<td class="lines-num"><span data-line-number="3"></span></td>`+ 939 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">C</span>`+"\n"+`</code></td>`+ 940 `</tr>`+ 941 `</tbody>`+ 942 `</table>`+ 943 `</div>`+ 944 `</div>`+ 945 `<p></p>`, 946 localMetas, 947 ) 948 949 testRender( 950 "first "+commitFilePreview+" second "+commitFilePreview+" third "+commitFilePreview, 951 `<p>first </p>`+ 952 `<div class="file-preview-box">`+ 953 `<div class="header">`+ 954 `<div>`+ 955 `<a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" class="muted" rel="nofollow">path/to/file.go</a>`+ 956 `</div>`+ 957 `<span class="text grey">`+ 958 `Lines 2 to 3 in <a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20" class="text black" rel="nofollow">190d949</a>`+ 959 `</span>`+ 960 `</div>`+ 961 `<div class="ui table">`+ 962 `<table class="file-preview">`+ 963 `<tbody>`+ 964 `<tr>`+ 965 `<td class="lines-num"><span data-line-number="2"></span></td>`+ 966 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">B</span>`+"\n"+`</code></td>`+ 967 `</tr>`+ 968 `<tr>`+ 969 `<td class="lines-num"><span data-line-number="3"></span></td>`+ 970 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">C</span>`+"\n"+`</code></td>`+ 971 `</tr>`+ 972 `</tbody>`+ 973 `</table>`+ 974 `</div>`+ 975 `</div>`+ 976 `<p> second </p>`+ 977 `<div class="file-preview-box">`+ 978 `<div class="header">`+ 979 `<div>`+ 980 `<a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" class="muted" rel="nofollow">path/to/file.go</a>`+ 981 `</div>`+ 982 `<span class="text grey">`+ 983 `Lines 2 to 3 in <a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20" class="text black" rel="nofollow">190d949</a>`+ 984 `</span>`+ 985 `</div>`+ 986 `<div class="ui table">`+ 987 `<table class="file-preview">`+ 988 `<tbody>`+ 989 `<tr>`+ 990 `<td class="lines-num"><span data-line-number="2"></span></td>`+ 991 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">B</span>`+"\n"+`</code></td>`+ 992 `</tr>`+ 993 `<tr>`+ 994 `<td class="lines-num"><span data-line-number="3"></span></td>`+ 995 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">C</span>`+"\n"+`</code></td>`+ 996 `</tr>`+ 997 `</tbody>`+ 998 `</table>`+ 999 `</div>`+ 1000 `</div>`+ 1001 `<p> third </p>`+ 1002 `<div class="file-preview-box">`+ 1003 `<div class="header">`+ 1004 `<div>`+ 1005 `<a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" class="muted" rel="nofollow">path/to/file.go</a>`+ 1006 `</div>`+ 1007 `<span class="text grey">`+ 1008 `Lines 2 to 3 in <a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20" class="text black" rel="nofollow">190d949</a>`+ 1009 `</span>`+ 1010 `</div>`+ 1011 `<div class="ui table">`+ 1012 `<table class="file-preview">`+ 1013 `<tbody>`+ 1014 `<tr>`+ 1015 `<td class="lines-num"><span data-line-number="2"></span></td>`+ 1016 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">B</span>`+"\n"+`</code></td>`+ 1017 `</tr>`+ 1018 `<tr>`+ 1019 `<td class="lines-num"><span data-line-number="3"></span></td>`+ 1020 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">C</span>`+"\n"+`</code></td>`+ 1021 `</tr>`+ 1022 `</tbody>`+ 1023 `</table>`+ 1024 `</div>`+ 1025 `</div>`+ 1026 `<p></p>`, 1027 localMetas, 1028 ) 1029 }) 1030 1031 commitFileURL := util.URLJoin(markup.TestRepoURL, "src", "commit", "c9913120ed2c1e27c1d7752ecdb7a504dc7cf6be", "path", "to", "file.md") 1032 1033 t.Run("rendered file with ?display=source", func(t *testing.T) { 1034 testRender( 1035 commitFileURL+"?display=source"+"#L1-L2", 1036 `<p></p>`+ 1037 `<div class="file-preview-box">`+ 1038 `<div class="header">`+ 1039 `<div>`+ 1040 `<a href="http://localhost:3000/gogits/gogs/src/commit/c9913120ed2c1e27c1d7752ecdb7a504dc7cf6be/path/to/file.md?display=source#L1-L2" class="muted" rel="nofollow">path/to/file.md</a>`+ 1041 `</div>`+ 1042 `<span class="text grey">`+ 1043 `Lines 1 to 2 in <a href="http://localhost:3000/gogits/gogs/src/commit/c9913120ed2c1e27c1d7752ecdb7a504dc7cf6be" class="text black" rel="nofollow">c991312</a>`+ 1044 `</span>`+ 1045 `</div>`+ 1046 `<div class="ui table">`+ 1047 `<table class="file-preview">`+ 1048 `<tbody>`+ 1049 `<tr>`+ 1050 `<td class="lines-num"><span data-line-number="1"></span></td>`+ 1051 `<td class="lines-code chroma"><code class="code-inner"><span class="gh"># A`+"\n"+`</span></code></td>`+ 1052 `</tr>`+ 1053 `<tr>`+ 1054 `<td class="lines-num"><span data-line-number="2"></span></td>`+ 1055 `<td class="lines-code chroma"><code class="code-inner"><span class="gh"></span>B`+"\n"+`</code></td>`+ 1056 `</tr>`+ 1057 `</tbody>`+ 1058 `</table>`+ 1059 `</div>`+ 1060 `</div>`+ 1061 `<p></p>`, 1062 localMetas, 1063 ) 1064 }) 1065 1066 t.Run("rendered file without ?display=source", func(t *testing.T) { 1067 testRender( 1068 commitFileURL+"#L1-L2", 1069 `<p></p>`+ 1070 `<div class="file-preview-box">`+ 1071 `<div class="header">`+ 1072 `<div>`+ 1073 `<a href="http://localhost:3000/gogits/gogs/src/commit/c9913120ed2c1e27c1d7752ecdb7a504dc7cf6be/path/to/file.md?display=source#L1-L2" class="muted" rel="nofollow">path/to/file.md</a>`+ 1074 `</div>`+ 1075 `<span class="text grey">`+ 1076 `Lines 1 to 2 in <a href="http://localhost:3000/gogits/gogs/src/commit/c9913120ed2c1e27c1d7752ecdb7a504dc7cf6be" class="text black" rel="nofollow">c991312</a>`+ 1077 `</span>`+ 1078 `</div>`+ 1079 `<div class="ui table">`+ 1080 `<table class="file-preview">`+ 1081 `<tbody>`+ 1082 `<tr>`+ 1083 `<td class="lines-num"><span data-line-number="1"></span></td>`+ 1084 `<td class="lines-code chroma"><code class="code-inner"><span class="gh"># A`+"\n"+`</span></code></td>`+ 1085 `</tr>`+ 1086 `<tr>`+ 1087 `<td class="lines-num"><span data-line-number="2"></span></td>`+ 1088 `<td class="lines-code chroma"><code class="code-inner"><span class="gh"></span>B`+"\n"+`</code></td>`+ 1089 `</tr>`+ 1090 `</tbody>`+ 1091 `</table>`+ 1092 `</div>`+ 1093 `</div>`+ 1094 `<p></p>`, 1095 localMetas, 1096 ) 1097 }) 1098 1099 commitFileURL = util.URLJoin(markup.TestRepoURL, "src", "commit", "190d9492934af498c3f669d6a2431dc5459e5b20", "path", "to", "file.go") 1100 1101 t.Run("normal file with ?display=source", func(t *testing.T) { 1102 testRender( 1103 commitFileURL+"?display=source"+"#L2-L3", 1104 `<p></p>`+ 1105 `<div class="file-preview-box">`+ 1106 `<div class="header">`+ 1107 `<div>`+ 1108 `<a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go?display=source#L2-L3" class="muted" rel="nofollow">path/to/file.go</a>`+ 1109 `</div>`+ 1110 `<span class="text grey">`+ 1111 `Lines 2 to 3 in <a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20" class="text black" rel="nofollow">190d949</a>`+ 1112 `</span>`+ 1113 `</div>`+ 1114 `<div class="ui table">`+ 1115 `<table class="file-preview">`+ 1116 `<tbody>`+ 1117 `<tr>`+ 1118 `<td class="lines-num"><span data-line-number="2"></span></td>`+ 1119 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">B</span>`+"\n"+`</code></td>`+ 1120 `</tr>`+ 1121 `<tr>`+ 1122 `<td class="lines-num"><span data-line-number="3"></span></td>`+ 1123 `<td class="lines-code chroma"><code class="code-inner"><span class="nx">C</span>`+"\n"+`</code></td>`+ 1124 `</tr>`+ 1125 `</tbody>`+ 1126 `</table>`+ 1127 `</div>`+ 1128 `</div>`+ 1129 `<p></p>`, 1130 localMetas, 1131 ) 1132 }) 1133 1134 commitFileURL = util.URLJoin(markup.TestRepoURL, "src", "commit", "eeb243c3395e1921c5d90e73bd739827251fc99d", "path", "to", "file%20%23.txt") 1135 1136 t.Run("file with strange characters in name", func(t *testing.T) { 1137 testRender( 1138 commitFileURL+"#L1", 1139 `<p></p>`+ 1140 `<div class="file-preview-box">`+ 1141 `<div class="header">`+ 1142 `<div>`+ 1143 `<a href="http://localhost:3000/gogits/gogs/src/commit/eeb243c3395e1921c5d90e73bd739827251fc99d/path/to/file%20%23.txt#L1" class="muted" rel="nofollow">path/to/file #.txt</a>`+ 1144 `</div>`+ 1145 `<span class="text grey">`+ 1146 `Line 1 in <a href="http://localhost:3000/gogits/gogs/src/commit/eeb243c3395e1921c5d90e73bd739827251fc99d" class="text black" rel="nofollow">eeb243c</a>`+ 1147 `</span>`+ 1148 `</div>`+ 1149 `<div class="ui table">`+ 1150 `<table class="file-preview">`+ 1151 `<tbody>`+ 1152 `<tr>`+ 1153 `<td class="lines-num"><span data-line-number="1"></span></td>`+ 1154 `<td class="lines-code chroma"><code class="code-inner">A`+"\n"+`</code></td>`+ 1155 `</tr>`+ 1156 `</tbody>`+ 1157 `</table>`+ 1158 `</div>`+ 1159 `</div>`+ 1160 `<p></p>`, 1161 localMetas, 1162 ) 1163 }) 1164}