Skip to content

Commit

Permalink
Fix /autolink test command for disabled links (#123)
Browse files Browse the repository at this point in the history
Also:
- Started a "library" of domain-specific tests, to be used as templates for configuration
- Added a template for ProductBoard
- Fixed a lint nit in client.go
  • Loading branch information
levb committed Jun 22, 2020
1 parent 1a6ac33 commit 50d8e37
Show file tree
Hide file tree
Showing 7 changed files with 401 additions and 316 deletions.
356 changes: 44 additions & 312 deletions server/autolink/autolink_test.go

Large diffs are not rendered by default.

142 changes: 142 additions & 0 deletions server/autolink/lib_credit_card_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package autolink_test

import (
"regexp"
"testing"

"github.com/stretchr/testify/assert"

"github.com/mattermost/mattermost-plugin-autolink/server/autolink"
)

const (
reVISA = `(?P<VISA>(?P<part1>4\d{3})[ -]?(?P<part2>\d{4})[ -]?(?P<part3>\d{4})[ -]?(?P<LastFour>[0-9]{4}))`
reMasterCard = `(?P<MasterCard>(?P<part1>5[1-5]\d{2})[ -]?(?P<part2>\d{4})[ -]?(?P<part3>\d{4})[ -]?(?P<LastFour>[0-9]{4}))`
reSwitchSolo = `(?P<SwitchSolo>(?P<part1>67\d{2})[ -]?(?P<part2>\d{4})[ -]?(?P<part3>\d{4})[ -]?(?P<LastFour>[0-9]{4}))`
reDiscover = `(?P<Discover>(?P<part1>6011)[ -]?(?P<part2>\d{4})[ -]?(?P<part3>\d{4})[ -]?(?P<LastFour>[0-9]{4}))`
reAMEX = `(?P<AMEX>(?P<part1>3[47]\d{2})[ -]?(?P<part2>\d{6})[ -]?(?P<part3>\d)(?P<LastFour>[0-9]{4}))`

replaceVISA = "VISA XXXX-XXXX-XXXX-$LastFour"
replaceMasterCard = "MasterCard XXXX-XXXX-XXXX-$LastFour"
replaceSwitchSolo = "Switch/Solo XXXX-XXXX-XXXX-$LastFour"
replaceDiscover = "Discover XXXX-XXXX-XXXX-$LastFour"
replaceAMEX = "American Express XXXX-XXXXXX-X$LastFour"
)

func TestCreditCardRegex(t *testing.T) {
for _, tc := range []struct {
Name string
RE string
Replace string
In string
Out string
}{
{"Visa happy spaces", reVISA, replaceVISA, " abc 4111 1111 1111 1234 def", " abc VISA XXXX-XXXX-XXXX-1234 def"},
{"Visa happy dashes", reVISA, replaceVISA, "4111-1111-1111-1234", "VISA XXXX-XXXX-XXXX-1234"},
{"Visa happy mixed", reVISA, replaceVISA, "41111111 1111-1234", "VISA XXXX-XXXX-XXXX-1234"},
{"Visa happy digits", reVISA, replaceVISA, "abc 4111111111111234 def", "abc VISA XXXX-XXXX-XXXX-1234 def"},
{"Visa non-match start", reVISA, replaceVISA, "3111111111111234", ""},
{"Visa non-match num digits", reVISA, replaceVISA, " 4111-1111-1111-123", ""},
{"Visa non-match sep", reVISA, replaceVISA, "4111=1111=1111_1234", ""},
{"Visa non-match no break before", reVISA, replaceVISA, "abc4111-1111-1111-1234", "abcVISA XXXX-XXXX-XXXX-1234"},
{"Visa non-match no break after", reVISA, replaceVISA, "4111-1111-1111-1234def", "VISA XXXX-XXXX-XXXX-1234def"},

{"MasterCard happy spaces", reMasterCard, replaceMasterCard, " abc 5111 1111 1111 1234 def", " abc MasterCard XXXX-XXXX-XXXX-1234 def"},
{"MasterCard happy dashes", reMasterCard, replaceMasterCard, "5211-1111-1111-1234", "MasterCard XXXX-XXXX-XXXX-1234"},
{"MasterCard happy mixed", reMasterCard, replaceMasterCard, "53111111 1111-1234", "MasterCard XXXX-XXXX-XXXX-1234"},
{"MasterCard happy digits", reMasterCard, replaceMasterCard, "abc 5411111111111234 def", "abc MasterCard XXXX-XXXX-XXXX-1234 def"},
{"MasterCard non-match start", reMasterCard, replaceMasterCard, "3111111111111234", ""},
{"MasterCard non-match num digits", reMasterCard, replaceMasterCard, " 5111-1111-1111-123", ""},
{"MasterCard non-match sep", reMasterCard, replaceMasterCard, "5111=1111=1111_1234", ""},
{"MasterCard non-match no break before", reMasterCard, replaceMasterCard, "abc5511-1111-1111-1234", "abcMasterCard XXXX-XXXX-XXXX-1234"},
{"MasterCard non-match no break after", reMasterCard, replaceMasterCard, "5111-1111-1111-1234def", "MasterCard XXXX-XXXX-XXXX-1234def"},

{"SwitchSolo happy spaces", reSwitchSolo, replaceSwitchSolo, " abc 6711 1111 1111 1234 def", " abc Switch/Solo XXXX-XXXX-XXXX-1234 def"},
{"SwitchSolo happy dashes", reSwitchSolo, replaceSwitchSolo, "6711-1111-1111-1234", "Switch/Solo XXXX-XXXX-XXXX-1234"},
{"SwitchSolo happy mixed", reSwitchSolo, replaceSwitchSolo, "67111111 1111-1234", "Switch/Solo XXXX-XXXX-XXXX-1234"},
{"SwitchSolo happy digits", reSwitchSolo, replaceSwitchSolo, "abc 6711111111111234 def", "abc Switch/Solo XXXX-XXXX-XXXX-1234 def"},
{"SwitchSolo non-match start", reSwitchSolo, replaceSwitchSolo, "3111111111111234", ""},
{"SwitchSolo non-match num digits", reSwitchSolo, replaceSwitchSolo, " 6711-1111-1111-123", ""},
{"SwitchSolo non-match sep", reSwitchSolo, replaceSwitchSolo, "6711=1111=1111_1234", ""},
{"SwitchSolo non-match no break before", reSwitchSolo, replaceSwitchSolo, "abc6711-1111-1111-1234", "abcSwitch/Solo XXXX-XXXX-XXXX-1234"},
{"SwitchSolo non-match no break after", reSwitchSolo, replaceSwitchSolo, "6711-1111-1111-1234def", "Switch/Solo XXXX-XXXX-XXXX-1234def"},

{"Discover happy spaces", reDiscover, replaceDiscover, " abc 6011 1111 1111 1234 def", " abc Discover XXXX-XXXX-XXXX-1234 def"},
{"Discover happy dashes", reDiscover, replaceDiscover, "6011-1111-1111-1234", "Discover XXXX-XXXX-XXXX-1234"},
{"Discover happy mixed", reDiscover, replaceDiscover, "60111111 1111-1234", "Discover XXXX-XXXX-XXXX-1234"},
{"Discover happy digits", reDiscover, replaceDiscover, "abc 6011111111111234 def", "abc Discover XXXX-XXXX-XXXX-1234 def"},
{"Discover non-match start", reDiscover, replaceDiscover, "3111111111111234", ""},
{"Discover non-match num digits", reDiscover, replaceDiscover, " 6011-1111-1111-123", ""},
{"Discover non-match sep", reDiscover, replaceDiscover, "6011=1111=1111_1234", ""},
{"Discover non-match no break before", reDiscover, replaceDiscover, "abc6011-1111-1111-1234", "abcDiscover XXXX-XXXX-XXXX-1234"},
{"Discover non-match no break after", reDiscover, replaceDiscover, "6011-1111-1111-1234def", "Discover XXXX-XXXX-XXXX-1234def"},

{"AMEX happy spaces", reAMEX, replaceAMEX, " abc 3411 123456 12345 def", " abc American Express XXXX-XXXXXX-X2345 def"},
{"AMEX happy dashes", reAMEX, replaceAMEX, "3711-123456-12345", "American Express XXXX-XXXXXX-X2345"},
{"AMEX happy mixed", reAMEX, replaceAMEX, "3411-123456 12345", "American Express XXXX-XXXXXX-X2345"},
{"AMEX happy digits", reAMEX, replaceAMEX, "abc 371112345612345 def", "abc American Express XXXX-XXXXXX-X2345 def"},
{"AMEX non-match start 41", reAMEX, replaceAMEX, "411112345612345", ""},
{"AMEX non-match start 31", reAMEX, replaceAMEX, "3111111111111234", ""},
{"AMEX non-match num digits", reAMEX, replaceAMEX, " 4111-1111-1111-123", ""},
{"AMEX non-match sep", reAMEX, replaceAMEX, "4111-1111=1111-1234", ""},
{"AMEX non-match no break before", reAMEX, replaceAMEX, "abc3711-123456-12345", "abcAmerican Express XXXX-XXXXXX-X2345"},
{"AMEX non-match no break after", reAMEX, replaceAMEX, "3711-123456-12345def", "American Express XXXX-XXXXXX-X2345def"},
} {
t.Run(tc.Name, func(t *testing.T) {
re := regexp.MustCompile(tc.RE)
result := re.ReplaceAllString(tc.In, tc.Replace)
if tc.Out != "" {
assert.Equal(t, tc.Out, result)
} else {
assert.Equal(t, tc.In, result)
}
})
}
}

func TestCreditCard(t *testing.T) {
var tests = []struct {
Name string
Link autolink.Autolink
inputMessage string
expectedMessage string
}{
{
"VISA happy",
autolink.Autolink{
Pattern: reVISA,
Template: replaceVISA,
},
"A credit card 4111-1111-2222-1234 mentioned",
"A credit card VISA XXXX-XXXX-XXXX-1234 mentioned",
}, {
"VISA",
autolink.Autolink{
Pattern: reVISA,
Template: replaceVISA,
DisableNonWordPrefix: true,
DisableNonWordSuffix: true,
},
"A credit card4111-1111-2222-3333mentioned",
"A credit cardVISA XXXX-XXXX-XXXX-3333mentioned",
}, {
"Multiple VISA replacements",
autolink.Autolink{
Pattern: reVISA,
Template: replaceVISA,
},
"Credit cards 4111-1111-2222-3333 4222-3333-4444-5678 mentioned",
"Credit cards VISA XXXX-XXXX-XXXX-3333 VISA XXXX-XXXX-XXXX-5678 mentioned",
},
}

for _, tt := range tests {
t.Run(tt.Name, func(t *testing.T) {
err := tt.Link.Compile()
actual := tt.Link.Replace(tt.inputMessage)

assert.Equal(t, tt.expectedMessage, actual)
assert.NoError(t, err)
})
}
}
125 changes: 125 additions & 0 deletions server/autolink/lib_jira_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package autolink_test

import (
"testing"

"github.com/mattermost/mattermost-plugin-autolink/server/autolink"
)

var jiraTests = []linkTest{
{
"Jira example",
autolink.Autolink{
Pattern: "(MM)(-)(?P<jira_id>\\d+)",
Template: "[MM-$jira_id](https://mattermost.atlassian.net/browse/MM-$jira_id)",
},
"Welcome MM-12345 should link!",
"Welcome [MM-12345](https://mattermost.atlassian.net/browse/MM-12345) should link!",
}, {
"Jira example 2 (within a ())",
autolink.Autolink{
Pattern: "(MM)(-)(?P<jira_id>\\d+)",
Template: "[MM-$jira_id](https://mattermost.atlassian.net/browse/MM-$jira_id)",
},
"Link in brackets should link (see MM-12345)",
"Link in brackets should link (see [MM-12345](https://mattermost.atlassian.net/browse/MM-12345))",
}, {
"Jira example 3 (before ,)",
autolink.Autolink{
Pattern: "(MM)(-)(?P<jira_id>\\d+)",
Template: "[MM-$jira_id](https://mattermost.atlassian.net/browse/MM-$jira_id)",
},
"Link a ticket MM-12345, before a comma",
"Link a ticket [MM-12345](https://mattermost.atlassian.net/browse/MM-12345), before a comma",
}, {
"Jira example 3 (at begin of the message)",
autolink.Autolink{
Pattern: "(MM)(-)(?P<jira_id>\\d+)",
Template: "[MM-$jira_id](https://mattermost.atlassian.net/browse/MM-$jira_id)",
},
"MM-12345 should link!",
"[MM-12345](https://mattermost.atlassian.net/browse/MM-12345) should link!",
}, {
"Pattern word prefix and suffix disabled",
autolink.Autolink{
Pattern: "(?P<previous>^|\\s)(MM)(-)(?P<jira_id>\\d+)",
Template: "${previous}[MM-$jira_id](https://mattermost.atlassian.net/browse/MM-$jira_id)",
DisableNonWordPrefix: true,
DisableNonWordSuffix: true,
},
"Welcome MM-12345 should link!",
"Welcome [MM-12345](https://mattermost.atlassian.net/browse/MM-12345) should link!",
}, {
"Pattern word prefix and suffix disabled (at begin of the message)",
autolink.Autolink{
Pattern: "(?P<previous>^|\\s)(MM)(-)(?P<jira_id>\\d+)",
Template: "${previous}[MM-$jira_id](https://mattermost.atlassian.net/browse/MM-$jira_id)",
DisableNonWordPrefix: true,
DisableNonWordSuffix: true,
},
"MM-12345 should link!",
"[MM-12345](https://mattermost.atlassian.net/browse/MM-12345) should link!",
}, {
"Pattern word prefix and suffix enable (in the middle of other text)",
autolink.Autolink{
Pattern: "(MM)(-)(?P<jira_id>\\d+)",
Template: "[MM-$jira_id](https://mattermost.atlassian.net/browse/MM-$jira_id)",
},
"WelcomeMM-12345should not link!",
"WelcomeMM-12345should not link!",
}, {
"Pattern word prefix and suffix disabled (in the middle of other text)",
autolink.Autolink{
Pattern: "(MM)(-)(?P<jira_id>\\d+)",
Template: "[MM-$jira_id](https://mattermost.atlassian.net/browse/MM-$jira_id)",
DisableNonWordPrefix: true,
DisableNonWordSuffix: true,
},
"WelcomeMM-12345should link!",
"Welcome[MM-12345](https://mattermost.atlassian.net/browse/MM-12345)should link!",
}, {
"Not relinking",
autolink.Autolink{
Pattern: "(MM)(-)(?P<jira_id>\\d+)",
Template: "[MM-$jira_id](https://mattermost.atlassian.net/browse/MM-$jira_id)",
},
"Welcome [MM-12345](https://mattermost.atlassian.net/browse/MM-12345) should not re-link!",
"Welcome [MM-12345](https://mattermost.atlassian.net/browse/MM-12345) should not re-link!",
}, {
"Url replacement",
autolink.Autolink{
Pattern: "(https://mattermost.atlassian.net/browse/)(MM)(-)(?P<jira_id>\\d+)",
Template: "[MM-$jira_id](https://mattermost.atlassian.net/browse/MM-$jira_id)",
},
"Welcome https://mattermost.atlassian.net/browse/MM-12345 should link!",
"Welcome [MM-12345](https://mattermost.atlassian.net/browse/MM-12345) should link!",
}, {
"Url replacement multiple times",
autolink.Autolink{
Pattern: "(https://mattermost.atlassian.net/browse/)(MM)(-)(?P<jira_id>\\d+)",
Template: "[MM-$jira_id](https://mattermost.atlassian.net/browse/MM-$jira_id)",
},
"Welcome https://mattermost.atlassian.net/browse/MM-12345. should link https://mattermost.atlassian.net/browse/MM-12346 !",
"Welcome [MM-12345](https://mattermost.atlassian.net/browse/MM-12345). should link [MM-12346](https://mattermost.atlassian.net/browse/MM-12346) !",
}, {
"Url replacement multiple times and at beginning",
autolink.Autolink{
Pattern: "(https:\\/\\/mattermost.atlassian.net\\/browse\\/)(MM)(-)(?P<jira_id>\\d+)",
Template: "[MM-$jira_id](https://mattermost.atlassian.net/browse/MM-$jira_id)",
},
"https://mattermost.atlassian.net/browse/MM-12345 https://mattermost.atlassian.net/browse/MM-12345",
"[MM-12345](https://mattermost.atlassian.net/browse/MM-12345) [MM-12345](https://mattermost.atlassian.net/browse/MM-12345)",
}, {
"Url replacement at end",
autolink.Autolink{
Pattern: "(https://mattermost.atlassian.net/browse/)(MM)(-)(?P<jira_id>\\d+)",
Template: "[MM-$jira_id](https://mattermost.atlassian.net/browse/MM-$jira_id)",
},
"Welcome https://mattermost.atlassian.net/browse/MM-12345",
"Welcome [MM-12345](https://mattermost.atlassian.net/browse/MM-12345)",
},
}

func TestJira(t *testing.T) {
testLinks(t, jiraTests...)
}
41 changes: 41 additions & 0 deletions server/autolink/lib_productboard_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package autolink_test

import (
"testing"

"github.com/mattermost/mattermost-plugin-autolink/server/autolink"
)

var productboardLink = autolink.Autolink{
Pattern: `(?P<url>https://mattermost\.productboard\.com/.+)`,
Template: "[ProductBoard link]($url)",
WordMatch: true,
}

var productboardTests = []linkTest{
{
"Url replacement",
productboardLink,
"Welcome to https://mattermost.productboard.com/somepage should link!",
"Welcome to [ProductBoard link](https://mattermost.productboard.com/somepage) should link!",
}, {
"Not relinking",
productboardLink,
"Welcome to [other link](https://mattermost.productboard.com/somepage) should not re-link!",
"Welcome to [other link](https://mattermost.productboard.com/somepage) should not re-link!",
}, {
"Word boundary happy",
productboardLink,
"Welcome to (https://mattermost.productboard.com/somepage) should link!",
"Welcome to ([ProductBoard link](https://mattermost.productboard.com/somepage)) should link!",
}, {
"Word boundary un-happy",
productboardLink,
"Welcome to (BADhttps://mattermost.productboard.com/somepage) should not link!",
"Welcome to (BADhttps://mattermost.productboard.com/somepage) should not link!",
},
}

func TestProductBoard(t *testing.T) {
testLinks(t, productboardTests...)
}
41 changes: 41 additions & 0 deletions server/autolink/lib_social_security_number_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package autolink_test

import (
"regexp"
"testing"

"github.com/stretchr/testify/assert"
)

const (
reSSN = `(?P<SSN>(?P<part1>\d{3})[ -]?(?P<part2>\d{2})[ -]?(?P<LastFour>[0-9]{4}))`
replaceSSN = `XXX-XX-$LastFour`
)

func TestSocialSecurityNumberRegex(t *testing.T) {
for _, tc := range []struct {
Name string
RE string
Replace string
In string
Out string
}{
{"SSN happy spaces", reSSN, replaceSSN, " abc 652 47 3356 def", " abc XXX-XX-3356 def"},
{"SSN happy dashes", reSSN, replaceSSN, " abc 652-47-3356 def", " abc XXX-XX-3356 def"},
{"SSN happy digits", reSSN, replaceSSN, " abc 652473356 def", " abc XXX-XX-3356 def"},
{"SSN happy mixed1", reSSN, replaceSSN, " abc 65247-3356 def", " abc XXX-XX-3356 def"},
{"SSN happy mixed2", reSSN, replaceSSN, " abc 652 47-3356 def", " abc XXX-XX-3356 def"},
{"SSN non-match 19-09-9999", reSSN, replaceSSN, " abc 19-09-9999 def", " abc 19-09-9999 def"},
{"SSN non-match 652_47-3356", reSSN, replaceSSN, " abc 652_47-3356 def", " abc 652_47-3356 def"},
} {
t.Run(tc.Name, func(t *testing.T) {
re := regexp.MustCompile(tc.RE)
result := re.ReplaceAllString(tc.In, tc.Replace)
if tc.Out != "" {
assert.Equal(t, tc.Out, result)
} else {
assert.Equal(t, tc.In, result)
}
})
}
}
2 changes: 1 addition & 1 deletion server/autolinkclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func NewClientPlugin(api PluginAPI) *Client {

func (c *Client) Add(links ...autolink.Autolink) error {
for _, link := range links {
linkBytes, err := json.Marshal(&link)
linkBytes, err := json.Marshal(link)
if err != nil {
return err
}
Expand Down
10 changes: 7 additions & 3 deletions server/autolinkplugin/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,16 +207,20 @@ func executeTest(p *Plugin, c *plugin.Context, header *model.CommandArgs, args .
restOfCommand := header.Command[10:] // "/autolink "
restOfCommand = restOfCommand[strings.Index(restOfCommand, args[0])+len(args[0]):]
orig := strings.TrimSpace(restOfCommand)
out := ""
out := fmt.Sprintf("- Original: `%s`\n", orig)

for _, ref := range refs {
l := links[ref]
l.Disabled = false
err = l.Compile()
if err != nil {
return responsef("failed to compile link %s: %v", l.DisplayName(), err)
}
replaced := l.Replace(orig)
if replaced == orig {
out += fmt.Sprintf("- %s: _no change_\n", l.DisplayName())
out += fmt.Sprintf("- Link %s: _no change_\n", l.DisplayName())
} else {
out += fmt.Sprintf("- %s: `%s`\n", l.DisplayName(), replaced)
out += fmt.Sprintf("- Link %s: changed to `%s`\n", l.DisplayName(), replaced)
orig = replaced
}
}
Expand Down

0 comments on commit 50d8e37

Please sign in to comment.