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

references_test.go 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. // Copyright 2019 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 references
  5. import (
  6. "testing"
  7. "code.gitea.io/gitea/modules/setting"
  8. "github.com/stretchr/testify/assert"
  9. )
  10. type testFixture struct {
  11. input string
  12. expected []testResult
  13. }
  14. type testResult struct {
  15. Index int64
  16. Owner string
  17. Name string
  18. Issue string
  19. IsPull bool
  20. Action XRefAction
  21. RefLocation *RefSpan
  22. ActionLocation *RefSpan
  23. }
  24. func TestFindAllIssueReferences(t *testing.T) {
  25. fixtures := []testFixture{
  26. {
  27. "Simply closes: #29 yes",
  28. []testResult{
  29. {29, "", "", "29", false, XRefActionCloses, &RefSpan{Start: 15, End: 18}, &RefSpan{Start: 7, End: 13}},
  30. },
  31. },
  32. {
  33. "Simply closes: !29 yes",
  34. []testResult{
  35. {29, "", "", "29", true, XRefActionCloses, &RefSpan{Start: 15, End: 18}, &RefSpan{Start: 7, End: 13}},
  36. },
  37. },
  38. {
  39. " #124 yes, this is a reference.",
  40. []testResult{
  41. {124, "", "", "124", false, XRefActionNone, &RefSpan{Start: 0, End: 4}, nil},
  42. },
  43. },
  44. {
  45. "```\nThis is a code block.\n#723 no, it's a code block.```",
  46. []testResult{},
  47. },
  48. {
  49. "This `#724` no, it's inline code.",
  50. []testResult{},
  51. },
  52. {
  53. "This user3/repo4#200 yes.",
  54. []testResult{
  55. {200, "user3", "repo4", "200", false, XRefActionNone, &RefSpan{Start: 5, End: 20}, nil},
  56. },
  57. },
  58. {
  59. "This user3/repo4!200 yes.",
  60. []testResult{
  61. {200, "user3", "repo4", "200", true, XRefActionNone, &RefSpan{Start: 5, End: 20}, nil},
  62. },
  63. },
  64. {
  65. "This [one](#919) no, this is a URL fragment.",
  66. []testResult{},
  67. },
  68. {
  69. "This [two](/user2/repo1/issues/921) yes.",
  70. []testResult{
  71. {921, "user2", "repo1", "921", false, XRefActionNone, nil, nil},
  72. },
  73. },
  74. {
  75. "This [three](/user2/repo1/pulls/922) yes.",
  76. []testResult{
  77. {922, "user2", "repo1", "922", true, XRefActionNone, nil, nil},
  78. },
  79. },
  80. {
  81. "This [four](http://gitea.com:3000/user3/repo4/issues/203) yes.",
  82. []testResult{
  83. {203, "user3", "repo4", "203", false, XRefActionNone, nil, nil},
  84. },
  85. },
  86. {
  87. "This [five](http://github.com/user3/repo4/issues/204) no.",
  88. []testResult{},
  89. },
  90. {
  91. "This http://gitea.com:3000/user4/repo5/201 no, bad URL.",
  92. []testResult{},
  93. },
  94. {
  95. "This http://gitea.com:3000/user4/repo5/pulls/202 yes.",
  96. []testResult{
  97. {202, "user4", "repo5", "202", true, XRefActionNone, nil, nil},
  98. },
  99. },
  100. {
  101. "This http://GiTeA.COM:3000/user4/repo6/pulls/205 yes.",
  102. []testResult{
  103. {205, "user4", "repo6", "205", true, XRefActionNone, nil, nil},
  104. },
  105. },
  106. {
  107. "Reopens #15 yes",
  108. []testResult{
  109. {15, "", "", "15", false, XRefActionReopens, &RefSpan{Start: 8, End: 11}, &RefSpan{Start: 0, End: 7}},
  110. },
  111. },
  112. {
  113. "This closes #20 for you yes",
  114. []testResult{
  115. {20, "", "", "20", false, XRefActionCloses, &RefSpan{Start: 12, End: 15}, &RefSpan{Start: 5, End: 11}},
  116. },
  117. },
  118. {
  119. "Do you fix user6/repo6#300 ? yes",
  120. []testResult{
  121. {300, "user6", "repo6", "300", false, XRefActionCloses, &RefSpan{Start: 11, End: 26}, &RefSpan{Start: 7, End: 10}},
  122. },
  123. },
  124. {
  125. "For 999 #1235 no keyword, but yes",
  126. []testResult{
  127. {1235, "", "", "1235", false, XRefActionNone, &RefSpan{Start: 8, End: 13}, nil},
  128. },
  129. },
  130. {
  131. "Which abc. #9434 same as above",
  132. []testResult{
  133. {9434, "", "", "9434", false, XRefActionNone, &RefSpan{Start: 11, End: 16}, nil},
  134. },
  135. },
  136. {
  137. "This closes #600 and reopens #599",
  138. []testResult{
  139. {600, "", "", "600", false, XRefActionCloses, &RefSpan{Start: 12, End: 16}, &RefSpan{Start: 5, End: 11}},
  140. {599, "", "", "599", false, XRefActionReopens, &RefSpan{Start: 29, End: 33}, &RefSpan{Start: 21, End: 28}},
  141. },
  142. },
  143. }
  144. testFixtures(t, fixtures, "default")
  145. type alnumFixture struct {
  146. input string
  147. issue string
  148. refLocation *RefSpan
  149. action XRefAction
  150. actionLocation *RefSpan
  151. }
  152. alnumFixtures := []alnumFixture{
  153. {
  154. "This ref ABC-123 is alphanumeric",
  155. "ABC-123", &RefSpan{Start: 9, End: 16},
  156. XRefActionNone, nil,
  157. },
  158. {
  159. "This closes ABCD-1234 alphanumeric",
  160. "ABCD-1234", &RefSpan{Start: 12, End: 21},
  161. XRefActionCloses, &RefSpan{Start: 5, End: 11},
  162. },
  163. }
  164. for _, fixture := range alnumFixtures {
  165. found, ref := FindRenderizableReferenceAlphanumeric(fixture.input)
  166. if fixture.issue == "" {
  167. assert.False(t, found, "Failed to parse: {%s}", fixture.input)
  168. } else {
  169. assert.True(t, found, "Failed to parse: {%s}", fixture.input)
  170. assert.Equal(t, fixture.issue, ref.Issue, "Failed to parse: {%s}", fixture.input)
  171. assert.Equal(t, fixture.refLocation, ref.RefLocation, "Failed to parse: {%s}", fixture.input)
  172. assert.Equal(t, fixture.action, ref.Action, "Failed to parse: {%s}", fixture.input)
  173. assert.Equal(t, fixture.actionLocation, ref.ActionLocation, "Failed to parse: {%s}", fixture.input)
  174. }
  175. }
  176. }
  177. func testFixtures(t *testing.T, fixtures []testFixture, context string) {
  178. // Save original value for other tests that may rely on it
  179. prevURL := setting.AppURL
  180. setting.AppURL = "https://gitea.com:3000/"
  181. for _, fixture := range fixtures {
  182. expraw := make([]*rawReference, len(fixture.expected))
  183. for i, e := range fixture.expected {
  184. expraw[i] = &rawReference{
  185. index: e.Index,
  186. owner: e.Owner,
  187. name: e.Name,
  188. isPull: e.IsPull,
  189. action: e.Action,
  190. issue: e.Issue,
  191. refLocation: e.RefLocation,
  192. actionLocation: e.ActionLocation,
  193. }
  194. }
  195. expref := rawToIssueReferenceList(expraw)
  196. refs := FindAllIssueReferencesMarkdown(fixture.input)
  197. assert.EqualValues(t, expref, refs, "[%s] Failed to parse: {%s}", context, fixture.input)
  198. rawrefs := findAllIssueReferencesMarkdown(fixture.input)
  199. assert.EqualValues(t, expraw, rawrefs, "[%s] Failed to parse: {%s}", context, fixture.input)
  200. }
  201. // Restore for other tests that may rely on the original value
  202. setting.AppURL = prevURL
  203. }
  204. func TestRegExp_mentionPattern(t *testing.T) {
  205. trueTestCases := []struct {
  206. pat string
  207. exp string
  208. }{
  209. {"@Unknwon", "@Unknwon"},
  210. {"@ANT_123", "@ANT_123"},
  211. {"@xxx-DiN0-z-A..uru..s-xxx", "@xxx-DiN0-z-A..uru..s-xxx"},
  212. {" @lol ", "@lol"},
  213. {" @Te-st", "@Te-st"},
  214. {"(@gitea)", "@gitea"},
  215. {"[@gitea]", "@gitea"},
  216. {"@gitea! this", "@gitea"},
  217. {"@gitea? this", "@gitea"},
  218. {"@gitea. this", "@gitea"},
  219. {"@gitea, this", "@gitea"},
  220. {"@gitea; this", "@gitea"},
  221. {"@gitea!\nthis", "@gitea"},
  222. {"\n@gitea?\nthis", "@gitea"},
  223. {"\t@gitea.\nthis", "@gitea"},
  224. {"@gitea,\nthis", "@gitea"},
  225. {"@gitea;\nthis", "@gitea"},
  226. {"@gitea!", "@gitea"},
  227. {"@gitea?", "@gitea"},
  228. {"@gitea.", "@gitea"},
  229. {"@gitea,", "@gitea"},
  230. {"@gitea;", "@gitea"},
  231. }
  232. falseTestCases := []string{
  233. "@ 0",
  234. "@ ",
  235. "@",
  236. "",
  237. "ABC",
  238. "@.ABC",
  239. "/home/gitea/@gitea",
  240. "\"@gitea\"",
  241. "@@gitea",
  242. "@gitea!this",
  243. "@gitea?this",
  244. "@gitea,this",
  245. "@gitea;this",
  246. }
  247. for _, testCase := range trueTestCases {
  248. found := mentionPattern.FindStringSubmatch(testCase.pat)
  249. assert.Len(t, found, 2)
  250. assert.Equal(t, testCase.exp, found[1])
  251. }
  252. for _, testCase := range falseTestCases {
  253. res := mentionPattern.MatchString(testCase)
  254. assert.False(t, res, "[%s] should be false", testCase)
  255. }
  256. }
  257. func TestRegExp_issueNumericPattern(t *testing.T) {
  258. trueTestCases := []string{
  259. "#1234",
  260. "#0",
  261. "#1234567890987654321",
  262. " #12",
  263. "#12:",
  264. "ref: #12: msg",
  265. }
  266. falseTestCases := []string{
  267. "# 1234",
  268. "# 0",
  269. "# ",
  270. "#",
  271. "#ABC",
  272. "#1A2B",
  273. "",
  274. "ABC",
  275. }
  276. for _, testCase := range trueTestCases {
  277. assert.True(t, issueNumericPattern.MatchString(testCase))
  278. }
  279. for _, testCase := range falseTestCases {
  280. assert.False(t, issueNumericPattern.MatchString(testCase))
  281. }
  282. }
  283. func TestRegExp_issueAlphanumericPattern(t *testing.T) {
  284. trueTestCases := []string{
  285. "ABC-1234",
  286. "A-1",
  287. "RC-80",
  288. "ABCDEFGHIJ-1234567890987654321234567890",
  289. "ABC-123.",
  290. "(ABC-123)",
  291. "[ABC-123]",
  292. "ABC-123:",
  293. }
  294. falseTestCases := []string{
  295. "RC-08",
  296. "PR-0",
  297. "ABCDEFGHIJK-1",
  298. "PR_1",
  299. "",
  300. "#ABC",
  301. "",
  302. "ABC",
  303. "GG-",
  304. "rm-1",
  305. "/home/gitea/ABC-1234",
  306. "MY-STRING-ABC-123",
  307. }
  308. for _, testCase := range trueTestCases {
  309. assert.True(t, issueAlphanumericPattern.MatchString(testCase))
  310. }
  311. for _, testCase := range falseTestCases {
  312. assert.False(t, issueAlphanumericPattern.MatchString(testCase))
  313. }
  314. }
  315. func TestCustomizeCloseKeywords(t *testing.T) {
  316. fixtures := []testFixture{
  317. {
  318. "Simplemente cierra: #29 yes",
  319. []testResult{
  320. {29, "", "", "29", false, XRefActionCloses, &RefSpan{Start: 20, End: 23}, &RefSpan{Start: 12, End: 18}},
  321. },
  322. },
  323. {
  324. "Closes: #123 no, this English.",
  325. []testResult{
  326. {123, "", "", "123", false, XRefActionNone, &RefSpan{Start: 8, End: 12}, nil},
  327. },
  328. },
  329. {
  330. "Cerró user6/repo6#300 yes",
  331. []testResult{
  332. {300, "user6", "repo6", "300", false, XRefActionCloses, &RefSpan{Start: 7, End: 22}, &RefSpan{Start: 0, End: 6}},
  333. },
  334. },
  335. {
  336. "Reabre user3/repo4#200 yes",
  337. []testResult{
  338. {200, "user3", "repo4", "200", false, XRefActionReopens, &RefSpan{Start: 7, End: 22}, &RefSpan{Start: 0, End: 6}},
  339. },
  340. },
  341. }
  342. issueKeywordsOnce.Do(func() {})
  343. doNewKeywords([]string{"cierra", "cerró"}, []string{"reabre"})
  344. testFixtures(t, fixtures, "spanish")
  345. // Restore default settings
  346. doNewKeywords(setting.Repository.PullRequest.CloseKeywords, setting.Repository.PullRequest.ReopenKeywords)
  347. }
  348. func TestParseCloseKeywords(t *testing.T) {
  349. // Test parsing of CloseKeywords and ReopenKeywords
  350. assert.Len(t, parseKeywords([]string{""}), 0)
  351. assert.Len(t, parseKeywords([]string{" aa ", " bb ", "99", "#", "", "this is", "cc"}), 3)
  352. for _, test := range []struct {
  353. pattern string
  354. match string
  355. expected string
  356. }{
  357. {"close", "This PR will close ", "close"},
  358. {"cerró", "cerró ", "cerró"},
  359. {"cerró", "AQUÍ SE CERRÓ: ", "CERRÓ"},
  360. {"закрывается", "закрывается ", "закрывается"},
  361. {"κλείνει", "κλείνει: ", "κλείνει"},
  362. {"关闭", "关闭 ", "关闭"},
  363. {"閉じます", "閉じます ", "閉じます"},
  364. {",$!", "", ""},
  365. {"1234", "", ""},
  366. } {
  367. // The patern only needs to match the part that precedes the reference.
  368. // getCrossReference() takes care of finding the reference itself.
  369. pat := makeKeywordsPat([]string{test.pattern})
  370. if test.expected == "" {
  371. assert.Nil(t, pat)
  372. } else {
  373. assert.NotNil(t, pat)
  374. res := pat.FindAllStringSubmatch(test.match, -1)
  375. assert.Len(t, res, 1)
  376. assert.Len(t, res[0], 2)
  377. assert.EqualValues(t, test.expected, res[0][1])
  378. }
  379. }
  380. }