gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // Copyright 2023 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package templates
  4. import (
  5. "context"
  6. "html/template"
  7. "os"
  8. "strings"
  9. "testing"
  10. "code.gitea.io/gitea/models/issues"
  11. "code.gitea.io/gitea/models/repo"
  12. user_model "code.gitea.io/gitea/models/user"
  13. "code.gitea.io/gitea/modules/markup"
  14. "code.gitea.io/gitea/modules/reqctx"
  15. "code.gitea.io/gitea/modules/setting"
  16. "code.gitea.io/gitea/modules/test"
  17. "code.gitea.io/gitea/modules/translation"
  18. "github.com/stretchr/testify/assert"
  19. )
  20. func testInput() string {
  21. s := ` space @mention-user<SPACE><SPACE>
  22. /just/a/path.bin
  23. https://example.com/file.bin
  24. [local link](file.bin)
  25. [remote link](https://example.com)
  26. [[local link|file.bin]]
  27. [[remote link|https://example.com]]
  28. ![local image](image.jpg)
  29. ![remote image](https://example.com/image.jpg)
  30. [[local image|image.jpg]]
  31. [[remote link|https://example.com/image.jpg]]
  32. https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
  33. com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
  34. https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
  35. com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
  36. :+1:
  37. mail@domain.com
  38. @mention-user test
  39. #123
  40. space<SPACE><SPACE>
  41. `
  42. return strings.ReplaceAll(s, "<SPACE>", " ")
  43. }
  44. func TestMain(m *testing.M) {
  45. setting.Markdown.RenderOptionsComment.ShortIssuePattern = true
  46. markup.Init(&markup.RenderHelperFuncs{
  47. IsUsernameMentionable: func(ctx context.Context, username string) bool {
  48. return username == "mention-user"
  49. },
  50. })
  51. os.Exit(m.Run())
  52. }
  53. func newTestRenderUtils(t *testing.T) *RenderUtils {
  54. ctx := reqctx.NewRequestContextForTest(t.Context())
  55. ctx.SetContextValue(translation.ContextKey, &translation.MockLocale{})
  56. return NewRenderUtils(ctx)
  57. }
  58. func TestRenderRepoComment(t *testing.T) {
  59. mockRepo := &repo.Repository{
  60. ID: 1, OwnerName: "user13", Name: "repo11",
  61. Owner: &user_model.User{ID: 13, Name: "user13"},
  62. Units: []*repo.RepoUnit{},
  63. }
  64. t.Run("RenderCommitBody", func(t *testing.T) {
  65. defer test.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
  66. type args struct {
  67. msg string
  68. }
  69. tests := []struct {
  70. name string
  71. args args
  72. want template.HTML
  73. }{
  74. {
  75. name: "multiple lines",
  76. args: args{
  77. msg: "first line\nsecond line",
  78. },
  79. want: "second line",
  80. },
  81. {
  82. name: "multiple lines with leading newlines",
  83. args: args{
  84. msg: "\n\n\n\nfirst line\nsecond line",
  85. },
  86. want: "second line",
  87. },
  88. {
  89. name: "multiple lines with trailing newlines",
  90. args: args{
  91. msg: "first line\nsecond line\n\n\n",
  92. },
  93. want: "second line",
  94. },
  95. }
  96. ut := newTestRenderUtils(t)
  97. for _, tt := range tests {
  98. t.Run(tt.name, func(t *testing.T) {
  99. assert.Equalf(t, tt.want, ut.RenderCommitBody(tt.args.msg, mockRepo), "RenderCommitBody(%v, %v)", tt.args.msg, nil)
  100. })
  101. }
  102. expected := `/just/a/path.bin
  103. <a href="https://example.com/file.bin">https://example.com/file.bin</a>
  104. [local link](file.bin)
  105. [remote link](<a href="https://example.com">https://example.com</a>)
  106. [[local link|file.bin]]
  107. [[remote link|<a href="https://example.com">https://example.com</a>]]
  108. ![local image](image.jpg)
  109. ![remote image](<a href="https://example.com/image.jpg">https://example.com/image.jpg</a>)
  110. [[local image|image.jpg]]
  111. [[remote link|<a href="https://example.com/image.jpg">https://example.com/image.jpg</a>]]
  112. <a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" class="compare"><code>88fc37a3c0...12fc37a3c0 (hash)</code></a>
  113. com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
  114. <a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" class="commit"><code>88fc37a3c0</code></a>
  115. com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
  116. <span class="emoji" aria-label="thumbs up">👍</span>
  117. <a href="mailto:mail@domain.com">mail@domain.com</a>
  118. <a href="/mention-user">@mention-user</a> test
  119. <a href="/user13/repo11/issues/123" class="ref-issue">#123</a>
  120. space`
  121. assert.Equal(t, expected, string(newTestRenderUtils(t).RenderCommitBody(testInput(), mockRepo)))
  122. })
  123. t.Run("RenderCommitMessage", func(t *testing.T) {
  124. expected := `space <a href="/mention-user" data-markdown-generated-content="">@mention-user</a> `
  125. assert.EqualValues(t, expected, newTestRenderUtils(t).RenderCommitMessage(testInput(), mockRepo))
  126. })
  127. t.Run("RenderCommitMessageLinkSubject", func(t *testing.T) {
  128. expected := `<a href="https://example.com/link" class="muted">space </a><a href="/mention-user" data-markdown-generated-content="">@mention-user</a>`
  129. assert.EqualValues(t, expected, newTestRenderUtils(t).RenderCommitMessageLinkSubject(testInput(), "https://example.com/link", mockRepo))
  130. })
  131. t.Run("RenderIssueTitle", func(t *testing.T) {
  132. defer test.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
  133. expected := ` space @mention-user<SPACE><SPACE>
  134. /just/a/path.bin
  135. https://example.com/file.bin
  136. [local link](file.bin)
  137. [remote link](https://example.com)
  138. [[local link|file.bin]]
  139. [[remote link|https://example.com]]
  140. ![local image](image.jpg)
  141. ![remote image](https://example.com/image.jpg)
  142. [[local image|image.jpg]]
  143. [[remote link|https://example.com/image.jpg]]
  144. https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
  145. com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
  146. https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
  147. com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
  148. <span class="emoji" aria-label="thumbs up">👍</span>
  149. mail@domain.com
  150. @mention-user test
  151. <a href="/user13/repo11/issues/123" class="ref-issue">#123</a>
  152. space<SPACE><SPACE>
  153. `
  154. expected = strings.ReplaceAll(expected, "<SPACE>", " ")
  155. assert.Equal(t, expected, string(newTestRenderUtils(t).RenderIssueTitle(testInput(), mockRepo)))
  156. })
  157. }
  158. func TestRenderMarkdownToHtml(t *testing.T) {
  159. defer test.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
  160. expected := `<p>space <a href="/mention-user" rel="nofollow">@mention-user</a><br/>
  161. /just/a/path.bin
  162. <a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a>
  163. <a href="/file.bin" rel="nofollow">local link</a>
  164. <a href="https://example.com" rel="nofollow">remote link</a>
  165. <a href="/file.bin" rel="nofollow">local link</a>
  166. <a href="https://example.com" rel="nofollow">remote link</a>
  167. <a href="/image.jpg" target="_blank" rel="nofollow noopener"><img src="/image.jpg" alt="local image"/></a>
  168. <a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a>
  169. <a href="/image.jpg" rel="nofollow"><img src="/image.jpg" title="local image" alt="local image"/></a>
  170. <a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt="remote link"/></a>
  171. <a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" rel="nofollow"><code>88fc37a3c0...12fc37a3c0 (hash)</code></a>
  172. com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
  173. <a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" rel="nofollow"><code>88fc37a3c0</code></a>
  174. com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
  175. <span class="emoji" aria-label="thumbs up">👍</span>
  176. <a href="mailto:mail@domain.com" rel="nofollow">mail@domain.com</a>
  177. <a href="/mention-user" rel="nofollow">@mention-user</a> test
  178. #123
  179. space</p>
  180. `
  181. assert.Equal(t, expected, string(newTestRenderUtils(t).MarkdownToHtml(testInput())))
  182. }
  183. func TestRenderLabels(t *testing.T) {
  184. ut := newTestRenderUtils(t)
  185. label := &issues.Label{ID: 123, Name: "label-name", Color: "label-color"}
  186. issue := &issues.Issue{}
  187. expected := `/owner/repo/issues?labels=123`
  188. assert.Contains(t, ut.RenderLabels([]*issues.Label{label}, "/owner/repo", issue), expected)
  189. label = &issues.Label{ID: 123, Name: "label-name", Color: "label-color"}
  190. issue = &issues.Issue{IsPull: true}
  191. expected = `/owner/repo/pulls?labels=123`
  192. assert.Contains(t, ut.RenderLabels([]*issues.Label{label}, "/owner/repo", issue), expected)
  193. expectedLabel := `<a href="&lt;&gt;" class="ui label " style="color: #fff !important; background-color: label-color !important;" data-tooltip-content title=""><span class="gt-ellipsis">label-name</span></a>`
  194. assert.Equal(t, expectedLabel, string(ut.RenderLabelWithLink(label, "<>")))
  195. assert.Equal(t, expectedLabel, string(ut.RenderLabelWithLink(label, template.URL("<>"))))
  196. label = &issues.Label{ID: 123, Name: "</>", Exclusive: true}
  197. expectedLabel = `<a href="" class="ui label scope-parent" data-tooltip-content title=""><div class="ui label scope-left" style="color: #fff !important; background-color: #000000 !important">&lt;</div><div class="ui label scope-right" style="color: #fff !important; background-color: #000000 !important">&gt;</div></a>`
  198. assert.Equal(t, expectedLabel, string(ut.RenderLabelWithLink(label, "")))
  199. label = &issues.Label{ID: 123, Name: "</>", Exclusive: true, ExclusiveOrder: 1}
  200. expectedLabel = `<a href="" class="ui label scope-parent" data-tooltip-content title=""><div class="ui label scope-left" style="color: #fff !important; background-color: #000000 !important">&lt;</div><div class="ui label scope-middle" style="color: #fff !important; background-color: #000000 !important">&gt;</div><div class="ui label scope-right">1</div></a>`
  201. assert.Equal(t, expectedLabel, string(ut.RenderLabelWithLink(label, "")))
  202. }
  203. func TestUserMention(t *testing.T) {
  204. markup.RenderBehaviorForTesting.DisableAdditionalAttributes = true
  205. rendered := newTestRenderUtils(t).MarkdownToHtml("@no-such-user @mention-user @mention-user")
  206. assert.Equal(t, `<p>@no-such-user <a href="/mention-user" rel="nofollow">@mention-user</a> <a href="/mention-user" rel="nofollow">@mention-user</a></p>`, strings.TrimSpace(string(rendered)))
  207. }