You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

html_test.go 14 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package markup_test
  5. import (
  6. "fmt"
  7. "strconv"
  8. "strings"
  9. "testing"
  10. . "code.gitea.io/gitea/modules/markup"
  11. _ "code.gitea.io/gitea/modules/markup/markdown"
  12. "code.gitea.io/gitea/modules/setting"
  13. "code.gitea.io/gitea/modules/util"
  14. "github.com/stretchr/testify/assert"
  15. )
  16. const AppURL = "http://localhost:3000/"
  17. const Repo = "gogits/gogs"
  18. const AppSubURL = AppURL + Repo + "/"
  19. var numericMetas = map[string]string{
  20. "format": "https://someurl.com/{user}/{repo}/{index}",
  21. "user": "someUser",
  22. "repo": "someRepo",
  23. "style": IssueNameStyleNumeric,
  24. }
  25. var alphanumericMetas = map[string]string{
  26. "format": "https://someurl.com/{user}/{repo}/{index}",
  27. "user": "someUser",
  28. "repo": "someRepo",
  29. "style": IssueNameStyleAlphanumeric,
  30. }
  31. // numericLink an HTML to a numeric-style issue
  32. func numericIssueLink(baseURL string, index int) string {
  33. return link(util.URLJoin(baseURL, strconv.Itoa(index)), fmt.Sprintf("#%d", index))
  34. }
  35. // alphanumLink an HTML link to an alphanumeric-style issue
  36. func alphanumIssueLink(baseURL string, name string) string {
  37. return link(util.URLJoin(baseURL, name), name)
  38. }
  39. // urlContentsLink an HTML link whose contents is the target URL
  40. func urlContentsLink(href string) string {
  41. return link(href, href)
  42. }
  43. // link an HTML link
  44. func link(href, contents string) string {
  45. return fmt.Sprintf("<a href=\"%s\">%s</a>", href, contents)
  46. }
  47. func testRenderIssueIndexPattern(t *testing.T, input, expected string, opts RenderIssueIndexPatternOptions) {
  48. if len(opts.URLPrefix) == 0 {
  49. opts.URLPrefix = AppSubURL
  50. }
  51. actual := string(RenderIssueIndexPattern([]byte(input), opts))
  52. assert.Equal(t, expected, actual)
  53. }
  54. func TestRender_IssueIndexPattern(t *testing.T) {
  55. // numeric: render inputs without valid mentions
  56. test := func(s string) {
  57. testRenderIssueIndexPattern(t, s, s, RenderIssueIndexPatternOptions{})
  58. testRenderIssueIndexPattern(t, s, s, RenderIssueIndexPatternOptions{Metas: numericMetas})
  59. }
  60. // should not render anything when there are no mentions
  61. test("")
  62. test("this is a test")
  63. test("test 123 123 1234")
  64. test("#")
  65. test("# # #")
  66. test("# 123")
  67. test("#abcd")
  68. test("##1234")
  69. test("test#1234")
  70. test("#1234test")
  71. test(" test #1234test")
  72. // should not render issue mention without leading space
  73. test("test#54321 issue")
  74. // should not render issue mention without trailing space
  75. test("test #54321issue")
  76. }
  77. func TestRender_IssueIndexPattern2(t *testing.T) {
  78. setting.AppURL = AppURL
  79. setting.AppSubURL = AppSubURL
  80. // numeric: render inputs with valid mentions
  81. test := func(s, expectedFmt string, indices ...int) {
  82. links := make([]interface{}, len(indices))
  83. for i, index := range indices {
  84. links[i] = numericIssueLink(util.URLJoin(setting.AppSubURL, "issues"), index)
  85. }
  86. expectedNil := fmt.Sprintf(expectedFmt, links...)
  87. testRenderIssueIndexPattern(t, s, expectedNil, RenderIssueIndexPatternOptions{})
  88. for i, index := range indices {
  89. links[i] = numericIssueLink("https://someurl.com/someUser/someRepo/", index)
  90. }
  91. expectedNum := fmt.Sprintf(expectedFmt, links...)
  92. testRenderIssueIndexPattern(t, s, expectedNum, RenderIssueIndexPatternOptions{Metas: numericMetas})
  93. }
  94. // should render freestanding mentions
  95. test("#1234 test", "%s test", 1234)
  96. test("test #8 issue", "test %s issue", 8)
  97. test("test issue #1234", "test issue %s", 1234)
  98. // should render mentions in parentheses
  99. test("(#54321 issue)", "(%s issue)", 54321)
  100. test("test (#9801 extra) issue", "test (%s extra) issue", 9801)
  101. test("test (#1)", "test (%s)", 1)
  102. // should render multiple issue mentions in the same line
  103. test("#54321 #1243", "%s %s", 54321, 1243)
  104. test("wow (#54321 #1243)", "wow (%s %s)", 54321, 1243)
  105. test("(#4)(#5)", "(%s)(%s)", 4, 5)
  106. test("#1 (#4321) test", "%s (%s) test", 1, 4321)
  107. }
  108. func TestRender_IssueIndexPattern3(t *testing.T) {
  109. setting.AppURL = AppURL
  110. setting.AppSubURL = AppSubURL
  111. // alphanumeric: render inputs without valid mentions
  112. test := func(s string) {
  113. testRenderIssueIndexPattern(t, s, s, RenderIssueIndexPatternOptions{Metas: alphanumericMetas})
  114. }
  115. test("")
  116. test("this is a test")
  117. test("test 123 123 1234")
  118. test("#")
  119. test("##1234")
  120. test("# 123")
  121. test("#abcd")
  122. test("test #123")
  123. test("abc-1234") // issue prefix must be capital
  124. test("ABc-1234") // issue prefix must be _all_ capital
  125. test("ABCDEFGHIJK-1234") // the limit is 10 characters in the prefix
  126. test("ABC1234") // dash is required
  127. test("test ABC- test") // number is required
  128. test("test -1234 test") // prefix is required
  129. test("testABC-123 test") // leading space is required
  130. test("test ABC-123test") // trailing space is required
  131. test("ABC-0123") // no leading zero
  132. }
  133. func TestRender_IssueIndexPattern4(t *testing.T) {
  134. setting.AppURL = AppURL
  135. setting.AppSubURL = AppSubURL
  136. // alphanumeric: render inputs with valid mentions
  137. test := func(s, expectedFmt string, names ...string) {
  138. links := make([]interface{}, len(names))
  139. for i, name := range names {
  140. links[i] = alphanumIssueLink("https://someurl.com/someUser/someRepo/", name)
  141. }
  142. expected := fmt.Sprintf(expectedFmt, links...)
  143. testRenderIssueIndexPattern(t, s, expected, RenderIssueIndexPatternOptions{Metas: alphanumericMetas})
  144. }
  145. test("OTT-1234 test", "%s test", "OTT-1234")
  146. test("test T-12 issue", "test %s issue", "T-12")
  147. test("test issue ABCDEFGHIJ-1234567890", "test issue %s", "ABCDEFGHIJ-1234567890")
  148. }
  149. func TestRenderIssueIndexPatternWithDefaultURL(t *testing.T) {
  150. setting.AppURL = AppURL
  151. setting.AppSubURL = AppSubURL
  152. test := func(input string, expected string) {
  153. testRenderIssueIndexPattern(t, input, expected, RenderIssueIndexPatternOptions{
  154. DefaultURL: AppURL,
  155. })
  156. }
  157. test("hello #123 world",
  158. fmt.Sprintf(`<a rel="nofollow" href="%s">hello</a> `, AppURL)+
  159. fmt.Sprintf(`<a href="%sissues/123">#123</a> `, AppSubURL)+
  160. fmt.Sprintf(`<a rel="nofollow" href="%s">world</a>`, AppURL))
  161. test("hello (#123) world",
  162. fmt.Sprintf(`<a rel="nofollow" href="%s">hello </a>`, AppURL)+
  163. fmt.Sprintf(`(<a href="%sissues/123">#123</a>)`, AppSubURL)+
  164. fmt.Sprintf(`<a rel="nofollow" href="%s"> world</a>`, AppURL))
  165. }
  166. func TestRender_AutoLink(t *testing.T) {
  167. setting.AppURL = AppURL
  168. setting.AppSubURL = AppSubURL
  169. test := func(input, expected string) {
  170. buffer := RenderSpecialLink([]byte(input), setting.AppSubURL, nil, false)
  171. assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
  172. buffer = RenderSpecialLink([]byte(input), setting.AppSubURL, nil, true)
  173. assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
  174. }
  175. // render valid issue URLs
  176. test(util.URLJoin(setting.AppSubURL, "issues", "3333"),
  177. numericIssueLink(util.URLJoin(setting.AppSubURL, "issues"), 3333))
  178. // render external issue URLs
  179. for _, externalURL := range []string{
  180. "http://1111/2222/ssss-issues/3333?param=blah&blahh=333",
  181. "http://test.com/issues/33333",
  182. "https://issues/333"} {
  183. test(externalURL, externalURL)
  184. }
  185. // render valid commit URLs
  186. tmp := util.URLJoin(AppSubURL, "commit", "d8a994ef243349f321568f9e36d5c3f444b99cae")
  187. test(tmp, "<a href=\""+tmp+"\">d8a994ef24</a>")
  188. tmp += "#diff-2"
  189. test(tmp, "<a href=\""+tmp+"\">d8a994ef24 (diff-2)</a>")
  190. // render other commit URLs
  191. tmp = "https://external-link.gogs.io/gogs/gogs/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2"
  192. test(tmp, "<a href=\""+tmp+"\">d8a994ef24 (diff-2)</a>")
  193. }
  194. func TestRender_Commits(t *testing.T) {
  195. setting.AppURL = AppURL
  196. setting.AppSubURL = AppSubURL
  197. test := func(input, expected string) {
  198. buffer := RenderString(".md", input, setting.AppSubURL, nil)
  199. assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
  200. }
  201. var sha = "b6dd6210eaebc915fd5be5579c58cce4da2e2579"
  202. var commit = util.URLJoin(AppSubURL, "commit", sha)
  203. var subtree = util.URLJoin(commit, "src")
  204. var tree = strings.Replace(subtree, "/commit/", "/tree/", -1)
  205. var src = strings.Replace(subtree, "/commit/", "/src/", -1)
  206. test(sha, `<p><a href="`+commit+`" rel="nofollow">b6dd6210ea</a></p>`)
  207. test(sha[:7], `<p><a href="`+commit[:len(commit)-(40-7)]+`" rel="nofollow">b6dd621</a></p>`)
  208. test(sha[:39], `<p><a href="`+commit[:len(commit)-(40-39)]+`" rel="nofollow">b6dd6210ea</a></p>`)
  209. test(commit, `<p><a href="`+commit+`" rel="nofollow">b6dd6210ea</a></p>`)
  210. test(tree, `<p><a href="`+src+`" rel="nofollow">b6dd6210ea/src</a></p>`)
  211. test("commit "+sha, `<p>commit <a href="`+commit+`" rel="nofollow">b6dd6210ea</a></p>`)
  212. }
  213. func TestRender_CrossReferences(t *testing.T) {
  214. setting.AppURL = AppURL
  215. setting.AppSubURL = AppSubURL
  216. test := func(input, expected string) {
  217. buffer := RenderString("a.md", input, setting.AppSubURL, nil)
  218. assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
  219. }
  220. test(
  221. "gogits/gogs#12345",
  222. `<p><a href="`+util.URLJoin(AppURL, "gogits", "gogs", "issues", "12345")+`" rel="nofollow">gogits/gogs#12345</a></p>`)
  223. test(
  224. "go-gitea/gitea#12345",
  225. `<p><a href="`+util.URLJoin(AppURL, "go-gitea", "gitea", "issues", "12345")+`" rel="nofollow">go-gitea/gitea#12345</a></p>`)
  226. }
  227. func TestRender_FullIssueURLs(t *testing.T) {
  228. setting.AppURL = AppURL
  229. setting.AppSubURL = AppSubURL
  230. test := func(input, expected string) {
  231. result := RenderFullIssuePattern([]byte(input))
  232. assert.Equal(t, expected, string(result))
  233. }
  234. test("Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6",
  235. "Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6")
  236. test("Look here http://localhost:3000/person/repo/issues/4",
  237. `Look here <a href="http://localhost:3000/person/repo/issues/4">#4</a>`)
  238. test("http://localhost:3000/person/repo/issues/4#issuecomment-1234",
  239. `<a href="http://localhost:3000/person/repo/issues/4#issuecomment-1234">#4</a>`)
  240. }
  241. func TestRegExp_MentionPattern(t *testing.T) {
  242. trueTestCases := []string{
  243. "@Unknwon",
  244. "@ANT_123",
  245. "@xxx-DiN0-z-A..uru..s-xxx",
  246. " @lol ",
  247. " @Te/st",
  248. }
  249. falseTestCases := []string{
  250. "@ 0",
  251. "@ ",
  252. "@",
  253. "",
  254. "ABC",
  255. }
  256. for _, testCase := range trueTestCases {
  257. res := MentionPattern.MatchString(testCase)
  258. if !res {
  259. println()
  260. println(testCase)
  261. }
  262. assert.True(t, res)
  263. }
  264. for _, testCase := range falseTestCases {
  265. res := MentionPattern.MatchString(testCase)
  266. if res {
  267. println()
  268. println(testCase)
  269. }
  270. assert.False(t, res)
  271. }
  272. }
  273. func TestRegExp_IssueNumericPattern(t *testing.T) {
  274. trueTestCases := []string{
  275. "#1234",
  276. "#0",
  277. "#1234567890987654321",
  278. "[#1234]",
  279. }
  280. falseTestCases := []string{
  281. "# 1234",
  282. "# 0",
  283. "# ",
  284. "#",
  285. "#ABC",
  286. "#1A2B",
  287. "",
  288. "ABC",
  289. "[]",
  290. "[x]",
  291. }
  292. for _, testCase := range trueTestCases {
  293. assert.True(t, IssueNumericPattern.MatchString(testCase))
  294. }
  295. for _, testCase := range falseTestCases {
  296. assert.False(t, IssueNumericPattern.MatchString(testCase))
  297. }
  298. }
  299. func TestRegExp_IssueAlphanumericPattern(t *testing.T) {
  300. trueTestCases := []string{
  301. "ABC-1234",
  302. "A-1",
  303. "RC-80",
  304. "ABCDEFGHIJ-1234567890987654321234567890",
  305. "[JIRA-134]",
  306. }
  307. falseTestCases := []string{
  308. "RC-08",
  309. "PR-0",
  310. "ABCDEFGHIJK-1",
  311. "PR_1",
  312. "",
  313. "#ABC",
  314. "",
  315. "ABC",
  316. "GG-",
  317. "rm-1",
  318. "[]",
  319. }
  320. for _, testCase := range trueTestCases {
  321. assert.True(t, IssueAlphanumericPattern.MatchString(testCase))
  322. }
  323. for _, testCase := range falseTestCases {
  324. assert.False(t, IssueAlphanumericPattern.MatchString(testCase))
  325. }
  326. }
  327. func TestRegExp_Sha1CurrentPattern(t *testing.T) {
  328. trueTestCases := []string{
  329. "d8a994ef243349f321568f9e36d5c3f444b99cae",
  330. "abcdefabcdefabcdefabcdefabcdefabcdefabcd",
  331. }
  332. falseTestCases := []string{
  333. "test",
  334. "abcdefg",
  335. "abcdefghijklmnopqrstuvwxyzabcdefghijklmn",
  336. "abcdefghijklmnopqrstuvwxyzabcdefghijklmO",
  337. }
  338. for _, testCase := range trueTestCases {
  339. assert.True(t, Sha1CurrentPattern.MatchString(testCase))
  340. }
  341. for _, testCase := range falseTestCases {
  342. assert.False(t, Sha1CurrentPattern.MatchString(testCase))
  343. }
  344. }
  345. func TestRegExp_AnySHA1Pattern(t *testing.T) {
  346. testCases := map[string][]string{
  347. "https://github.com/jquery/jquery/blob/a644101ed04d0beacea864ce805e0c4f86ba1cd1/test/unit/event.js#L2703": {
  348. "https",
  349. "github.com",
  350. "jquery",
  351. "jquery",
  352. "blob",
  353. "a644101ed04d0beacea864ce805e0c4f86ba1cd1",
  354. "test/unit/event.js",
  355. "L2703",
  356. },
  357. "https://github.com/jquery/jquery/blob/a644101ed04d0beacea864ce805e0c4f86ba1cd1/test/unit/event.js": {
  358. "https",
  359. "github.com",
  360. "jquery",
  361. "jquery",
  362. "blob",
  363. "a644101ed04d0beacea864ce805e0c4f86ba1cd1",
  364. "test/unit/event.js",
  365. "",
  366. },
  367. "https://github.com/jquery/jquery/commit/0705be475092aede1eddae01319ec931fb9c65fc": {
  368. "https",
  369. "github.com",
  370. "jquery",
  371. "jquery",
  372. "commit",
  373. "0705be475092aede1eddae01319ec931fb9c65fc",
  374. "",
  375. "",
  376. },
  377. "https://github.com/jquery/jquery/tree/0705be475092aede1eddae01319ec931fb9c65fc/src": {
  378. "https",
  379. "github.com",
  380. "jquery",
  381. "jquery",
  382. "tree",
  383. "0705be475092aede1eddae01319ec931fb9c65fc",
  384. "src",
  385. "",
  386. },
  387. "https://try.gogs.io/gogs/gogs/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2": {
  388. "https",
  389. "try.gogs.io",
  390. "gogs",
  391. "gogs",
  392. "commit",
  393. "d8a994ef243349f321568f9e36d5c3f444b99cae",
  394. "",
  395. "diff-2",
  396. },
  397. }
  398. for k, v := range testCases {
  399. assert.Equal(t, AnySHA1Pattern.FindStringSubmatch(k)[1:], v)
  400. }
  401. }
  402. func TestMisc_IsSameDomain(t *testing.T) {
  403. setting.AppURL = AppURL
  404. setting.AppSubURL = AppSubURL
  405. var sha = "b6dd6210eaebc915fd5be5579c58cce4da2e2579"
  406. var commit = util.URLJoin(AppSubURL, "commit", sha)
  407. assert.True(t, IsSameDomain(commit))
  408. assert.False(t, IsSameDomain("http://google.com/ncr"))
  409. assert.False(t, IsSameDomain("favicon.ico"))
  410. }