From bb04fb55d75242c71a131998565a567e193a3d8c Mon Sep 17 00:00:00 2001
From: guillep2k <18600385+guillep2k@users.noreply.github.com>
Date: Sat, 9 Nov 2019 19:12:05 -0300
Subject: [PATCH] Enable punctuations ending mentions (#8889)

* Enable punctuations ending mentions

* Improve tests
---
 modules/references/references.go      |  2 +-
 modules/references/references_test.go | 47 ++++++++++++++++++++-------
 2 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/modules/references/references.go b/modules/references/references.go
index 58a8da2895..af0fe1aa0d 100644
--- a/modules/references/references.go
+++ b/modules/references/references.go
@@ -27,7 +27,7 @@ var (
 	// TODO: fix invalid linking issue
 
 	// mentionPattern matches all mentions in the form of "@user"
-	mentionPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(@[0-9a-zA-Z-_\.]+)(?:\s|$|\)|\])`)
+	mentionPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(@[0-9a-zA-Z-_]+|@[0-9a-zA-Z-_][0-9a-zA-Z-_.]+[0-9a-zA-Z-_])(?:\s|[:,;.?!]\s|[:,;.?!]?$|\)|\])`)
 	// issueNumericPattern matches string that references to a numeric issue, e.g. #1287
 	issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(#[0-9]+)(?:\s|$|\)|\]|:|\.(\s|$))`)
 	// issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234
diff --git a/modules/references/references_test.go b/modules/references/references_test.go
index 52e9b4ff52..d46c5e85d7 100644
--- a/modules/references/references_test.go
+++ b/modules/references/references_test.go
@@ -208,14 +208,32 @@ func testFixtures(t *testing.T, fixtures []testFixture, context string) {
 }
 
 func TestRegExp_mentionPattern(t *testing.T) {
-	trueTestCases := []string{
-		"@Unknwon",
-		"@ANT_123",
-		"@xxx-DiN0-z-A..uru..s-xxx",
-		"   @lol   ",
-		" @Te-st",
-		"(@gitea)",
-		"[@gitea]",
+	trueTestCases := []struct {
+		pat string
+		exp string
+	}{
+		{"@Unknwon", "@Unknwon"},
+		{"@ANT_123", "@ANT_123"},
+		{"@xxx-DiN0-z-A..uru..s-xxx", "@xxx-DiN0-z-A..uru..s-xxx"},
+		{"   @lol   ", "@lol"},
+		{" @Te-st", "@Te-st"},
+		{"(@gitea)", "@gitea"},
+		{"[@gitea]", "@gitea"},
+		{"@gitea! this", "@gitea"},
+		{"@gitea? this", "@gitea"},
+		{"@gitea. this", "@gitea"},
+		{"@gitea, this", "@gitea"},
+		{"@gitea; this", "@gitea"},
+		{"@gitea!\nthis", "@gitea"},
+		{"\n@gitea?\nthis", "@gitea"},
+		{"\t@gitea.\nthis", "@gitea"},
+		{"@gitea,\nthis", "@gitea"},
+		{"@gitea;\nthis", "@gitea"},
+		{"@gitea!", "@gitea"},
+		{"@gitea?", "@gitea"},
+		{"@gitea.", "@gitea"},
+		{"@gitea,", "@gitea"},
+		{"@gitea;", "@gitea"},
 	}
 	falseTestCases := []string{
 		"@ 0",
@@ -223,17 +241,24 @@ func TestRegExp_mentionPattern(t *testing.T) {
 		"@",
 		"",
 		"ABC",
+		"@.ABC",
 		"/home/gitea/@gitea",
 		"\"@gitea\"",
+		"@@gitea",
+		"@gitea!this",
+		"@gitea?this",
+		"@gitea,this",
+		"@gitea;this",
 	}
 
 	for _, testCase := range trueTestCases {
-		res := mentionPattern.MatchString(testCase)
-		assert.True(t, res)
+		found := mentionPattern.FindStringSubmatch(testCase.pat)
+		assert.Len(t, found, 2)
+		assert.Equal(t, testCase.exp, found[1])
 	}
 	for _, testCase := range falseTestCases {
 		res := mentionPattern.MatchString(testCase)
-		assert.False(t, res)
+		assert.False(t, res, "[%s] should be false", testCase)
 	}
 }