1e53fe85ad
* Add mutex to model.Post to guard against race conditions on Post.Props * Rename mutex * Add GetProp() method to Post * Fix more tests * Fix flaky test Benchmarks: BenchmarkPostPropsGet_indirect BenchmarkPostPropsGet_indirect-2 85026746 13.0 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_indirect-4 90273747 13.0 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_indirect-8 88324293 13.0 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_indirect-16 91427720 13.1 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_direct BenchmarkPostPropsGet_direct-2 1000000000 0.242 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_direct-4 1000000000 0.241 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_direct-8 1000000000 0.240 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_direct-16 1000000000 0.241 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsAdd_indirect BenchmarkPostPropsAdd_indirect-2 5602224 203 ns/op 336 B/op 2 allocs/op BenchmarkPostPropsAdd_indirect-4 5959496 206 ns/op 336 B/op 2 allocs/op BenchmarkPostPropsAdd_indirect-8 5833999 205 ns/op 336 B/op 2 allocs/op BenchmarkPostPropsAdd_indirect-16 5802493 225 ns/op 336 B/op 2 allocs/op BenchmarkPostPropsAdd_direct BenchmarkPostPropsAdd_direct-2 100000000 11.3 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsAdd_direct-4 100000000 11.3 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsAdd_direct-8 100000000 11.6 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsAdd_direct-16 99840794 11.4 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsDel_indirect BenchmarkPostPropsDel_indirect-2 18824002 61.9 ns/op 48 B/op 1 allocs/op BenchmarkPostPropsDel_indirect-4 19470736 63.8 ns/op 48 B/op 1 allocs/op BenchmarkPostPropsDel_indirect-8 17640460 65.3 ns/op 48 B/op 1 allocs/op BenchmarkPostPropsDel_indirect-16 18692962 65.4 ns/op 48 B/op 1 allocs/op BenchmarkPostPropsDel_direct BenchmarkPostPropsDel_direct-2 516257440 2.34 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsDel_direct-4 514865216 2.43 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsDel_direct-8 511330477 2.37 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsDel_direct-16 499504010 2.38 ns/op 0 B/op 0 allocs/op
852 lines
16 KiB
Go
852 lines
16 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package model
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestPostToJson(t *testing.T) {
|
|
o := Post{Id: NewId(), Message: NewId()}
|
|
j := o.ToJson()
|
|
ro := PostFromJson(strings.NewReader(j))
|
|
|
|
assert.NotNil(t, ro)
|
|
assert.Equal(t, &o, ro.Clone())
|
|
}
|
|
|
|
func TestPostFromJsonError(t *testing.T) {
|
|
ro := PostFromJson(strings.NewReader(""))
|
|
assert.Nil(t, ro)
|
|
}
|
|
|
|
func TestPostIsValid(t *testing.T) {
|
|
o := Post{}
|
|
maxPostSize := 10000
|
|
|
|
err := o.IsValid(maxPostSize)
|
|
require.NotNil(t, err)
|
|
|
|
o.Id = NewId()
|
|
err = o.IsValid(maxPostSize)
|
|
require.NotNil(t, err)
|
|
|
|
o.CreateAt = GetMillis()
|
|
err = o.IsValid(maxPostSize)
|
|
require.NotNil(t, err)
|
|
|
|
o.UpdateAt = GetMillis()
|
|
err = o.IsValid(maxPostSize)
|
|
require.NotNil(t, err)
|
|
|
|
o.UserId = NewId()
|
|
err = o.IsValid(maxPostSize)
|
|
require.NotNil(t, err)
|
|
|
|
o.ChannelId = NewId()
|
|
o.RootId = "123"
|
|
err = o.IsValid(maxPostSize)
|
|
require.NotNil(t, err)
|
|
|
|
o.RootId = ""
|
|
o.ParentId = "123"
|
|
err = o.IsValid(maxPostSize)
|
|
require.NotNil(t, err)
|
|
|
|
o.ParentId = NewId()
|
|
o.RootId = ""
|
|
err = o.IsValid(maxPostSize)
|
|
require.NotNil(t, err)
|
|
|
|
o.ParentId = ""
|
|
o.Message = strings.Repeat("0", maxPostSize+1)
|
|
err = o.IsValid(maxPostSize)
|
|
require.NotNil(t, err)
|
|
|
|
o.Message = strings.Repeat("0", maxPostSize)
|
|
err = o.IsValid(maxPostSize)
|
|
require.Nil(t, err)
|
|
|
|
o.Message = "test"
|
|
err = o.IsValid(maxPostSize)
|
|
require.Nil(t, err)
|
|
o.Type = "junk"
|
|
err = o.IsValid(maxPostSize)
|
|
require.NotNil(t, err)
|
|
|
|
o.Type = POST_CUSTOM_TYPE_PREFIX + "type"
|
|
err = o.IsValid(maxPostSize)
|
|
require.Nil(t, err)
|
|
}
|
|
|
|
func TestPostPreSave(t *testing.T) {
|
|
o := Post{Message: "test"}
|
|
o.PreSave()
|
|
|
|
require.NotEqual(t, 0, o.CreateAt)
|
|
|
|
past := GetMillis() - 1
|
|
o = Post{Message: "test", CreateAt: past}
|
|
o.PreSave()
|
|
|
|
require.LessOrEqual(t, o.CreateAt, past)
|
|
|
|
o.Etag()
|
|
}
|
|
|
|
func TestPostIsSystemMessage(t *testing.T) {
|
|
post1 := Post{Message: "test_1"}
|
|
post1.PreSave()
|
|
|
|
require.False(t, post1.IsSystemMessage())
|
|
|
|
post2 := Post{Message: "test_2", Type: POST_JOIN_LEAVE}
|
|
post2.PreSave()
|
|
|
|
require.True(t, post2.IsSystemMessage())
|
|
}
|
|
|
|
func TestPostChannelMentions(t *testing.T) {
|
|
post := Post{Message: "~a ~b ~b ~c/~d."}
|
|
assert.Equal(t, []string{"a", "b", "c", "d"}, post.ChannelMentions())
|
|
}
|
|
|
|
func TestPostSanitizeProps(t *testing.T) {
|
|
post1 := &Post{
|
|
Message: "test",
|
|
}
|
|
|
|
post1.SanitizeProps()
|
|
|
|
require.Nil(t, post1.GetProp(PROPS_ADD_CHANNEL_MEMBER))
|
|
|
|
post2 := &Post{
|
|
Message: "test",
|
|
Props: StringInterface{
|
|
PROPS_ADD_CHANNEL_MEMBER: "test",
|
|
},
|
|
}
|
|
|
|
post2.SanitizeProps()
|
|
|
|
require.Nil(t, post2.GetProp(PROPS_ADD_CHANNEL_MEMBER))
|
|
|
|
post3 := &Post{
|
|
Message: "test",
|
|
Props: StringInterface{
|
|
PROPS_ADD_CHANNEL_MEMBER: "no good",
|
|
"attachments": "good",
|
|
},
|
|
}
|
|
|
|
post3.SanitizeProps()
|
|
|
|
require.Nil(t, post3.GetProp(PROPS_ADD_CHANNEL_MEMBER))
|
|
|
|
require.NotNil(t, post3.GetProp("attachments"))
|
|
}
|
|
|
|
func TestPost_AttachmentsEqual(t *testing.T) {
|
|
post1 := &Post{}
|
|
post2 := &Post{}
|
|
for name, tc := range map[string]struct {
|
|
Attachments1 []*SlackAttachment
|
|
Attachments2 []*SlackAttachment
|
|
Expected bool
|
|
}{
|
|
"Empty": {
|
|
nil,
|
|
nil,
|
|
true,
|
|
},
|
|
"DifferentLength": {
|
|
[]*SlackAttachment{
|
|
{
|
|
Text: "Hello World",
|
|
},
|
|
},
|
|
nil,
|
|
false,
|
|
},
|
|
"EqualText": {
|
|
[]*SlackAttachment{
|
|
{
|
|
Text: "Hello World",
|
|
},
|
|
},
|
|
[]*SlackAttachment{
|
|
{
|
|
Text: "Hello World",
|
|
},
|
|
},
|
|
true,
|
|
},
|
|
"DifferentText": {
|
|
[]*SlackAttachment{
|
|
{
|
|
Text: "Hello World",
|
|
},
|
|
},
|
|
[]*SlackAttachment{
|
|
{
|
|
Text: "Hello World 2",
|
|
},
|
|
},
|
|
false,
|
|
},
|
|
"DifferentColor": {
|
|
[]*SlackAttachment{
|
|
{
|
|
Text: "Hello World",
|
|
Color: "#152313",
|
|
},
|
|
},
|
|
[]*SlackAttachment{
|
|
{
|
|
Text: "Hello World 2",
|
|
},
|
|
},
|
|
false,
|
|
},
|
|
"EqualFields": {
|
|
[]*SlackAttachment{
|
|
{
|
|
Fields: []*SlackAttachmentField{
|
|
{
|
|
Title: "Hello World",
|
|
Value: "FooBar",
|
|
},
|
|
{
|
|
Title: "Hello World2",
|
|
Value: "FooBar2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
[]*SlackAttachment{
|
|
{
|
|
Fields: []*SlackAttachmentField{
|
|
{
|
|
Title: "Hello World",
|
|
Value: "FooBar",
|
|
},
|
|
{
|
|
Title: "Hello World2",
|
|
Value: "FooBar2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
true,
|
|
},
|
|
"DifferentFields": {
|
|
[]*SlackAttachment{
|
|
{
|
|
Fields: []*SlackAttachmentField{
|
|
{
|
|
Title: "Hello World",
|
|
Value: "FooBar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
[]*SlackAttachment{
|
|
{
|
|
Fields: []*SlackAttachmentField{
|
|
{
|
|
Title: "Hello World",
|
|
Value: "FooBar",
|
|
Short: false,
|
|
},
|
|
{
|
|
Title: "Hello World2",
|
|
Value: "FooBar2",
|
|
Short: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
false,
|
|
},
|
|
"EqualActions": {
|
|
[]*SlackAttachment{
|
|
{
|
|
Actions: []*PostAction{
|
|
{
|
|
Name: "FooBar",
|
|
Options: []*PostActionOptions{
|
|
{
|
|
Text: "abcdef",
|
|
Value: "abcdef",
|
|
},
|
|
},
|
|
Integration: &PostActionIntegration{
|
|
URL: "http://localhost",
|
|
Context: map[string]interface{}{
|
|
"context": "foobar",
|
|
"test": 123,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
[]*SlackAttachment{
|
|
{
|
|
Actions: []*PostAction{
|
|
{
|
|
Name: "FooBar",
|
|
Options: []*PostActionOptions{
|
|
{
|
|
Text: "abcdef",
|
|
Value: "abcdef",
|
|
},
|
|
},
|
|
Integration: &PostActionIntegration{
|
|
URL: "http://localhost",
|
|
Context: map[string]interface{}{
|
|
"context": "foobar",
|
|
"test": 123,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
true,
|
|
},
|
|
"DifferentActions": {
|
|
[]*SlackAttachment{
|
|
{
|
|
Actions: []*PostAction{
|
|
{
|
|
Name: "FooBar",
|
|
Options: []*PostActionOptions{
|
|
{
|
|
Text: "abcdef",
|
|
Value: "abcdef",
|
|
},
|
|
},
|
|
Integration: &PostActionIntegration{
|
|
URL: "http://localhost",
|
|
Context: map[string]interface{}{
|
|
"context": "foobar",
|
|
"test": "mattermost",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
[]*SlackAttachment{
|
|
{
|
|
Actions: []*PostAction{
|
|
{
|
|
Name: "FooBar",
|
|
Options: []*PostActionOptions{
|
|
{
|
|
Text: "abcdef",
|
|
Value: "abcdef",
|
|
},
|
|
},
|
|
Integration: &PostActionIntegration{
|
|
URL: "http://localhost",
|
|
Context: map[string]interface{}{
|
|
"context": "foobar",
|
|
"test": 123,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
false,
|
|
},
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
post1.AddProp("attachments", tc.Attachments1)
|
|
post2.AddProp("attachments", tc.Attachments2)
|
|
assert.Equal(t, tc.Expected, post1.AttachmentsEqual(post2))
|
|
})
|
|
}
|
|
}
|
|
|
|
var markdownSample, markdownSampleWithRewrittenImageURLs string
|
|
|
|
func init() {
|
|
bytes, err := ioutil.ReadFile("testdata/markdown-sample.md")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
markdownSample = string(bytes)
|
|
|
|
bytes, err = ioutil.ReadFile("testdata/markdown-sample-with-rewritten-image-urls.md")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
markdownSampleWithRewrittenImageURLs = string(bytes)
|
|
}
|
|
|
|
func TestRewriteImageURLs(t *testing.T) {
|
|
for name, tc := range map[string]struct {
|
|
Markdown string
|
|
Expected string
|
|
}{
|
|
"Empty": {
|
|
Markdown: ``,
|
|
Expected: ``,
|
|
},
|
|
"NoImages": {
|
|
Markdown: `foo`,
|
|
Expected: `foo`,
|
|
},
|
|
"Link": {
|
|
Markdown: `[foo](/url)`,
|
|
Expected: `[foo](/url)`,
|
|
},
|
|
"Image": {
|
|
Markdown: `![foo](/url)`,
|
|
Expected: `![foo](rewritten:/url)`,
|
|
},
|
|
"SpacedURL": {
|
|
Markdown: `![foo]( /url )`,
|
|
Expected: `![foo]( rewritten:/url )`,
|
|
},
|
|
"Title": {
|
|
Markdown: `![foo](/url "title")`,
|
|
Expected: `![foo](rewritten:/url "title")`,
|
|
},
|
|
"Parentheses": {
|
|
Markdown: `![foo](/url(1) "title")`,
|
|
Expected: `![foo](rewritten:/url\(1\) "title")`,
|
|
},
|
|
"AngleBrackets": {
|
|
Markdown: `![foo](</url\<1\>\\> "title")`,
|
|
Expected: `![foo](<rewritten:/url\<1\>\\> "title")`,
|
|
},
|
|
"MultipleLines": {
|
|
Markdown: `![foo](
|
|
</url\<1\>\\>
|
|
"title"
|
|
)`,
|
|
Expected: `![foo](
|
|
<rewritten:/url\<1\>\\>
|
|
"title"
|
|
)`,
|
|
},
|
|
"ReferenceLink": {
|
|
Markdown: `[foo]: </url\<1\>\\> "title"
|
|
[foo]`,
|
|
Expected: `[foo]: </url\<1\>\\> "title"
|
|
[foo]`,
|
|
},
|
|
"ReferenceImage": {
|
|
Markdown: `[foo]: </url\<1\>\\> "title"
|
|
![foo]`,
|
|
Expected: `[foo]: <rewritten:/url\<1\>\\> "title"
|
|
![foo]`,
|
|
},
|
|
"MultipleReferenceImages": {
|
|
Markdown: `[foo]: </url1> "title"
|
|
[bar]: </url2>
|
|
[baz]: /url3 "title"
|
|
[qux]: /url4
|
|
![foo]![qux]`,
|
|
Expected: `[foo]: <rewritten:/url1> "title"
|
|
[bar]: </url2>
|
|
[baz]: /url3 "title"
|
|
[qux]: rewritten:/url4
|
|
![foo]![qux]`,
|
|
},
|
|
"DuplicateReferences": {
|
|
Markdown: `[foo]: </url1> "title"
|
|
[foo]: </url2>
|
|
[foo]: /url3 "title"
|
|
[foo]: /url4
|
|
![foo]![foo]![foo]`,
|
|
Expected: `[foo]: <rewritten:/url1> "title"
|
|
[foo]: </url2>
|
|
[foo]: /url3 "title"
|
|
[foo]: /url4
|
|
![foo]![foo]![foo]`,
|
|
},
|
|
"TrailingURL": {
|
|
Markdown: "![foo]\n\n[foo]: /url",
|
|
Expected: "![foo]\n\n[foo]: rewritten:/url",
|
|
},
|
|
"Sample": {
|
|
Markdown: markdownSample,
|
|
Expected: markdownSampleWithRewrittenImageURLs,
|
|
},
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
assert.Equal(t, tc.Expected, RewriteImageURLs(tc.Markdown, func(url string) string {
|
|
return "rewritten:" + url
|
|
}))
|
|
})
|
|
}
|
|
}
|
|
|
|
var rewriteImageURLsSink string
|
|
|
|
func BenchmarkRewriteImageURLs(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
rewriteImageURLsSink = RewriteImageURLs(markdownSample, func(url string) string {
|
|
return "rewritten:" + url
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPostShallowCopy(t *testing.T) {
|
|
var dst *Post
|
|
p := &Post{
|
|
Id: NewId(),
|
|
}
|
|
|
|
err := p.ShallowCopy(dst)
|
|
require.Error(t, err)
|
|
|
|
dst = &Post{}
|
|
err = p.ShallowCopy(dst)
|
|
require.NoError(t, err)
|
|
require.Equal(t, p, dst)
|
|
require.Condition(t, func() bool {
|
|
return p != dst
|
|
})
|
|
}
|
|
|
|
func TestPostClone(t *testing.T) {
|
|
p := &Post{
|
|
Id: NewId(),
|
|
}
|
|
|
|
pp := p.Clone()
|
|
require.Equal(t, p, pp)
|
|
require.Condition(t, func() bool {
|
|
return p != pp
|
|
})
|
|
require.Condition(t, func() bool {
|
|
return &p.propsMu != &pp.propsMu
|
|
})
|
|
}
|
|
|
|
func BenchmarkClonePost(b *testing.B) {
|
|
p := Post{}
|
|
for i := 0; i < b.N; i++ {
|
|
_ = p.Clone()
|
|
}
|
|
}
|
|
|
|
func BenchmarkPostPropsGet_indirect(b *testing.B) {
|
|
p := Post{
|
|
Props: make(StringInterface),
|
|
}
|
|
for i := 0; i < b.N; i++ {
|
|
_ = p.GetProps()
|
|
}
|
|
}
|
|
|
|
func BenchmarkPostPropsGet_direct(b *testing.B) {
|
|
p := Post{
|
|
Props: make(StringInterface),
|
|
}
|
|
for i := 0; i < b.N; i++ {
|
|
_ = p.Props
|
|
}
|
|
}
|
|
|
|
func BenchmarkPostPropsAdd_indirect(b *testing.B) {
|
|
p := Post{
|
|
Props: make(StringInterface),
|
|
}
|
|
for i := 0; i < b.N; i++ {
|
|
p.AddProp("test", "somevalue")
|
|
}
|
|
}
|
|
|
|
func BenchmarkPostPropsAdd_direct(b *testing.B) {
|
|
p := Post{
|
|
Props: make(StringInterface),
|
|
}
|
|
for i := 0; i < b.N; i++ {
|
|
p.Props["test"] = "somevalue"
|
|
}
|
|
}
|
|
|
|
func BenchmarkPostPropsDel_indirect(b *testing.B) {
|
|
p := Post{
|
|
Props: make(StringInterface),
|
|
}
|
|
p.AddProp("test", "somevalue")
|
|
for i := 0; i < b.N; i++ {
|
|
p.DelProp("test")
|
|
}
|
|
}
|
|
|
|
func BenchmarkPostPropsDel_direct(b *testing.B) {
|
|
p := Post{
|
|
Props: make(StringInterface),
|
|
}
|
|
for i := 0; i < b.N; i++ {
|
|
delete(p.Props, "test")
|
|
}
|
|
}
|
|
|
|
func BenchmarkPostPropGet_direct(b *testing.B) {
|
|
p := Post{
|
|
Props: make(StringInterface),
|
|
}
|
|
p.Props["somekey"] = "somevalue"
|
|
for i := 0; i < b.N; i++ {
|
|
_ = p.Props["somekey"]
|
|
}
|
|
}
|
|
|
|
func BenchmarkPostPropGet_indirect(b *testing.B) {
|
|
p := Post{
|
|
Props: make(StringInterface),
|
|
}
|
|
p.Props["somekey"] = "somevalue"
|
|
for i := 0; i < b.N; i++ {
|
|
_ = p.GetProp("somekey")
|
|
}
|
|
}
|
|
|
|
// TestPostPropsDataRace tries to trigger data race conditions related to Post.Props.
|
|
// It's meant to be run with the -race flag.
|
|
func TestPostPropsDataRace(t *testing.T) {
|
|
p := Post{Message: "test"}
|
|
|
|
wg := sync.WaitGroup{}
|
|
wg.Add(7)
|
|
|
|
go func() {
|
|
for i := 0; i < 100; i++ {
|
|
p.AddProp("test", "test")
|
|
}
|
|
wg.Done()
|
|
}()
|
|
|
|
go func() {
|
|
for i := 0; i < 100; i++ {
|
|
_ = p.GetProp("test")
|
|
}
|
|
wg.Done()
|
|
}()
|
|
|
|
go func() {
|
|
for i := 0; i < 100; i++ {
|
|
p.AddProp("test", "test2")
|
|
}
|
|
wg.Done()
|
|
}()
|
|
|
|
go func() {
|
|
for i := 0; i < 100; i++ {
|
|
_ = p.GetProps()["test"]
|
|
}
|
|
wg.Done()
|
|
}()
|
|
|
|
go func() {
|
|
for i := 0; i < 100; i++ {
|
|
p.DelProp("test")
|
|
}
|
|
wg.Done()
|
|
}()
|
|
|
|
go func() {
|
|
for i := 0; i < 100; i++ {
|
|
p.SetProps(make(StringInterface))
|
|
}
|
|
wg.Done()
|
|
}()
|
|
|
|
go func() {
|
|
for i := 0; i < 100; i++ {
|
|
_ = p.Clone()
|
|
}
|
|
wg.Done()
|
|
}()
|
|
|
|
wg.Wait()
|
|
}
|
|
|
|
func Test_findAtChannelMention(t *testing.T) {
|
|
testCases := []struct {
|
|
Name string
|
|
Message string
|
|
Mention string
|
|
Found bool
|
|
}{
|
|
{
|
|
"Returns mention for @here wrapped by spaces",
|
|
"hi guys @here wrapped by spaces",
|
|
"@here",
|
|
true,
|
|
},
|
|
{
|
|
"Returns mention for @all wrapped by spaces",
|
|
"hi guys @all wrapped by spaces",
|
|
"@all",
|
|
true,
|
|
},
|
|
{
|
|
"Returns mention for @channel wrapped by spaces",
|
|
"hi guys @channel wrapped by spaces",
|
|
"@channel",
|
|
true,
|
|
},
|
|
{
|
|
"Returns mention for @here wrapped by dash",
|
|
"-@here-",
|
|
"@here",
|
|
true,
|
|
},
|
|
{
|
|
"Returns mention for @all wrapped by back tick",
|
|
"`@all`",
|
|
"@all",
|
|
true,
|
|
},
|
|
{
|
|
"Returns mention for @channel wrapped by tags",
|
|
"<@channel>",
|
|
"@channel",
|
|
true,
|
|
},
|
|
{
|
|
"Returns mention for @channel wrapped by asterisks",
|
|
"*@channel*",
|
|
"@channel",
|
|
true,
|
|
},
|
|
{
|
|
"Does not return mention when prefixed by letters",
|
|
"hi@channel",
|
|
"",
|
|
false,
|
|
},
|
|
{
|
|
"Does not return mention when suffixed by letters",
|
|
"hi @channelanotherword",
|
|
"",
|
|
false,
|
|
},
|
|
{
|
|
"Returns mention when prefixed by word ending in special character",
|
|
"hi-@channel",
|
|
"@channel",
|
|
true,
|
|
},
|
|
{
|
|
"Returns mention when suffixed by word starting in special character",
|
|
"hi @channel-guys",
|
|
"@channel",
|
|
true,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.Name, func(t *testing.T) {
|
|
mention, found := findAtChannelMention(tc.Message)
|
|
assert.Equal(t, tc.Mention, mention)
|
|
assert.Equal(t, tc.Found, found)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPostDisableMentionHighlights(t *testing.T) {
|
|
post := &Post{}
|
|
|
|
testCases := []struct {
|
|
Name string
|
|
Message string
|
|
ExpectedProps StringInterface
|
|
ExpectedMention string
|
|
}{
|
|
{
|
|
"Does nothing for post with no mentions",
|
|
"Sample message with no mentions",
|
|
StringInterface(nil),
|
|
"",
|
|
},
|
|
{
|
|
"Sets POST_PROPS_MENTION_HIGHLIGHT_DISABLED and returns mention",
|
|
"Sample message with @here",
|
|
StringInterface{POST_PROPS_MENTION_HIGHLIGHT_DISABLED: true},
|
|
"@here",
|
|
},
|
|
{
|
|
"Sets POST_PROPS_MENTION_HIGHLIGHT_DISABLED and returns mention",
|
|
"Sample message with @channel",
|
|
StringInterface{POST_PROPS_MENTION_HIGHLIGHT_DISABLED: true},
|
|
"@channel",
|
|
},
|
|
{
|
|
"Sets POST_PROPS_MENTION_HIGHLIGHT_DISABLED and returns mention",
|
|
"Sample message with @all",
|
|
StringInterface{POST_PROPS_MENTION_HIGHLIGHT_DISABLED: true},
|
|
"@all",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.Name, func(t *testing.T) {
|
|
post.Message = tc.Message
|
|
mention := post.DisableMentionHighlights()
|
|
assert.Equal(t, tc.ExpectedMention, mention)
|
|
assert.Equal(t, tc.ExpectedProps, post.Props)
|
|
post.Props = StringInterface{}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPostPatchDisableMentionHighlights(t *testing.T) {
|
|
patch := &PostPatch{}
|
|
|
|
testCases := []struct {
|
|
Name string
|
|
Message string
|
|
ExpectedProps *StringInterface
|
|
}{
|
|
{
|
|
"Does nothing for post with no mentions",
|
|
"Sample message with no mentions",
|
|
nil,
|
|
},
|
|
{
|
|
"Sets POST_PROPS_MENTION_HIGHLIGHT_DISABLED",
|
|
"Sample message with @here",
|
|
&StringInterface{POST_PROPS_MENTION_HIGHLIGHT_DISABLED: true},
|
|
},
|
|
{
|
|
"Sets POST_PROPS_MENTION_HIGHLIGHT_DISABLED",
|
|
"Sample message with @channel",
|
|
&StringInterface{POST_PROPS_MENTION_HIGHLIGHT_DISABLED: true},
|
|
},
|
|
{
|
|
"Sets POST_PROPS_MENTION_HIGHLIGHT_DISABLED",
|
|
"Sample message with @all",
|
|
&StringInterface{POST_PROPS_MENTION_HIGHLIGHT_DISABLED: true},
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.Name, func(t *testing.T) {
|
|
patch.Message = &tc.Message
|
|
patch.DisableMentionHighlights()
|
|
if tc.ExpectedProps == nil {
|
|
assert.Nil(t, patch.Props)
|
|
} else {
|
|
assert.Equal(t, *tc.ExpectedProps, *patch.Props)
|
|
}
|
|
patch.Props = nil
|
|
})
|
|
}
|
|
}
|