mirror of
https://github.com/mattermost/mattermost.git
synced 2026-04-15 22:12:19 -04:00
281 lines
6.1 KiB
Go
281 lines
6.1 KiB
Go
|
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||
|
|
// See LICENSE.txt for license information.
|
||
|
|
|
||
|
|
package model
|
||
|
|
|
||
|
|
import (
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"github.com/stretchr/testify/assert"
|
||
|
|
"github.com/stretchr/testify/require"
|
||
|
|
)
|
||
|
|
|
||
|
|
func validView() *View {
|
||
|
|
return &View{
|
||
|
|
Id: NewId(),
|
||
|
|
ChannelId: NewId(),
|
||
|
|
CreatorId: NewId(),
|
||
|
|
Type: ViewTypeKanban,
|
||
|
|
Title: "My Kanban",
|
||
|
|
CreateAt: 1,
|
||
|
|
UpdateAt: 1,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestViewIsValid(t *testing.T) {
|
||
|
|
testCases := []struct {
|
||
|
|
Description string
|
||
|
|
View *View
|
||
|
|
Valid bool
|
||
|
|
}{
|
||
|
|
{
|
||
|
|
"valid view",
|
||
|
|
validView(),
|
||
|
|
true,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"missing id",
|
||
|
|
&View{
|
||
|
|
ChannelId: NewId(),
|
||
|
|
CreatorId: NewId(),
|
||
|
|
Type: ViewTypeKanban,
|
||
|
|
Title: "My Kanban",
|
||
|
|
CreateAt: 1,
|
||
|
|
UpdateAt: 1,
|
||
|
|
},
|
||
|
|
false,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"invalid id",
|
||
|
|
func() *View { v := validView(); v.Id = "invalid"; return v }(),
|
||
|
|
false,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"missing channel id",
|
||
|
|
func() *View { v := validView(); v.ChannelId = ""; return v }(),
|
||
|
|
false,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"invalid channel id",
|
||
|
|
func() *View { v := validView(); v.ChannelId = "invalid"; return v }(),
|
||
|
|
false,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"missing creator id",
|
||
|
|
func() *View { v := validView(); v.CreatorId = ""; return v }(),
|
||
|
|
false,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"invalid creator id",
|
||
|
|
func() *View { v := validView(); v.CreatorId = "invalid"; return v }(),
|
||
|
|
false,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"invalid type",
|
||
|
|
func() *View { v := validView(); v.Type = "invalid"; return v }(),
|
||
|
|
false,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"empty title",
|
||
|
|
func() *View { v := validView(); v.Title = ""; return v }(),
|
||
|
|
false,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"title at max length",
|
||
|
|
func() *View { v := validView(); v.Title = strings.Repeat("a", ViewTitleMaxRunes); return v }(),
|
||
|
|
true,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"title exceeds max length",
|
||
|
|
func() *View { v := validView(); v.Title = strings.Repeat("a", ViewTitleMaxRunes+1); return v }(),
|
||
|
|
false,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"description at max length",
|
||
|
|
func() *View {
|
||
|
|
v := validView()
|
||
|
|
v.Description = strings.Repeat("a", ViewDescriptionMaxRunes)
|
||
|
|
return v
|
||
|
|
}(),
|
||
|
|
true,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"description exceeds max length",
|
||
|
|
func() *View {
|
||
|
|
v := validView()
|
||
|
|
v.Description = strings.Repeat("a", ViewDescriptionMaxRunes+1)
|
||
|
|
return v
|
||
|
|
}(),
|
||
|
|
false,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"missing create_at",
|
||
|
|
func() *View { v := validView(); v.CreateAt = 0; return v }(),
|
||
|
|
false,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"missing update_at",
|
||
|
|
func() *View { v := validView(); v.UpdateAt = 0; return v }(),
|
||
|
|
false,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"valid view with props",
|
||
|
|
func() *View {
|
||
|
|
v := validView()
|
||
|
|
v.Props = StringInterface{"key": "value"}
|
||
|
|
return v
|
||
|
|
}(),
|
||
|
|
true,
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tc := range testCases {
|
||
|
|
t.Run(tc.Description, func(t *testing.T) {
|
||
|
|
if tc.Valid {
|
||
|
|
require.Nil(t, tc.View.IsValid())
|
||
|
|
} else {
|
||
|
|
require.NotNil(t, tc.View.IsValid())
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestViewPreSave(t *testing.T) {
|
||
|
|
t.Run("generates id if empty", func(t *testing.T) {
|
||
|
|
v := &View{Type: ViewTypeKanban, Title: "Kanban"}
|
||
|
|
v.PreSave()
|
||
|
|
assert.True(t, IsValidId(v.Id))
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("keeps existing id", func(t *testing.T) {
|
||
|
|
id := NewId()
|
||
|
|
v := &View{Id: id, Type: ViewTypeKanban, Title: "Kanban"}
|
||
|
|
v.PreSave()
|
||
|
|
assert.Equal(t, id, v.Id)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("sets create_at and update_at", func(t *testing.T) {
|
||
|
|
v := &View{Type: ViewTypeKanban, Title: "Kanban"}
|
||
|
|
v.PreSave()
|
||
|
|
assert.NotZero(t, v.CreateAt)
|
||
|
|
assert.Equal(t, v.CreateAt, v.UpdateAt)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("keeps existing create_at", func(t *testing.T) {
|
||
|
|
v := &View{Type: ViewTypeKanban, Title: "Kanban", CreateAt: 42}
|
||
|
|
v.PreSave()
|
||
|
|
assert.Equal(t, int64(42), v.CreateAt)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("sets delete_at to zero", func(t *testing.T) {
|
||
|
|
v := &View{Type: ViewTypeKanban, Title: "Kanban", DeleteAt: 99}
|
||
|
|
v.PreSave()
|
||
|
|
assert.Zero(t, v.DeleteAt)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestViewPreUpdate(t *testing.T) {
|
||
|
|
v := validView()
|
||
|
|
originalUpdateAt := v.UpdateAt
|
||
|
|
|
||
|
|
v.PreUpdate()
|
||
|
|
|
||
|
|
assert.Greater(t, v.UpdateAt, originalUpdateAt)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestViewClone(t *testing.T) {
|
||
|
|
t.Run("nil props clones without panicking", func(t *testing.T) {
|
||
|
|
v := validView()
|
||
|
|
v.Props = nil
|
||
|
|
clone := v.Clone()
|
||
|
|
require.NotNil(t, clone)
|
||
|
|
assert.Nil(t, clone.Props)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("scalar fields are equal", func(t *testing.T) {
|
||
|
|
v := validView()
|
||
|
|
clone := v.Clone()
|
||
|
|
assert.Equal(t, v.Id, clone.Id)
|
||
|
|
assert.Equal(t, v.ChannelId, clone.ChannelId)
|
||
|
|
assert.Equal(t, v.Title, clone.Title)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("props are independently copied", func(t *testing.T) {
|
||
|
|
v := validView()
|
||
|
|
v.Props = StringInterface{"key": "value"}
|
||
|
|
clone := v.Clone()
|
||
|
|
require.NotNil(t, clone.Props)
|
||
|
|
assert.NotSame(t, &v.Props, &clone.Props)
|
||
|
|
assert.Equal(t, v.Props["key"], clone.Props["key"])
|
||
|
|
|
||
|
|
clone.Props["key"] = "mutated"
|
||
|
|
assert.Equal(t, "value", v.Props["key"], "original Props must not be affected")
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestViewPatch(t *testing.T) {
|
||
|
|
testCases := []struct {
|
||
|
|
Description string
|
||
|
|
Patch *ViewPatch
|
||
|
|
Check func(t *testing.T, v *View)
|
||
|
|
}{
|
||
|
|
{
|
||
|
|
"patches title",
|
||
|
|
&ViewPatch{Title: NewPointer("New Title")},
|
||
|
|
func(t *testing.T, v *View) {
|
||
|
|
assert.Equal(t, "New Title", v.Title)
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"patches description",
|
||
|
|
&ViewPatch{Description: NewPointer("A description")},
|
||
|
|
func(t *testing.T, v *View) {
|
||
|
|
assert.Equal(t, "A description", v.Description)
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"patches sort_order",
|
||
|
|
&ViewPatch{SortOrder: NewPointer(5)},
|
||
|
|
func(t *testing.T, v *View) {
|
||
|
|
assert.Equal(t, 5, v.SortOrder)
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"patches props",
|
||
|
|
&ViewPatch{Props: &StringInterface{"foo": "bar"}},
|
||
|
|
func(t *testing.T, v *View) {
|
||
|
|
require.NotNil(t, v.Props)
|
||
|
|
assert.Equal(t, "bar", v.Props["foo"])
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"nil fields are not applied",
|
||
|
|
&ViewPatch{},
|
||
|
|
func(t *testing.T, v *View) {
|
||
|
|
assert.Equal(t, "My Kanban", v.Title)
|
||
|
|
assert.Empty(t, v.Description)
|
||
|
|
assert.Zero(t, v.SortOrder)
|
||
|
|
},
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tc := range testCases {
|
||
|
|
t.Run(tc.Description, func(t *testing.T) {
|
||
|
|
v := validView()
|
||
|
|
v.Patch(tc.Patch)
|
||
|
|
tc.Check(t, v)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
t.Run("patched props are independent from patch source", func(t *testing.T) {
|
||
|
|
patchProps := &StringInterface{"key": "value"}
|
||
|
|
v := validView()
|
||
|
|
v.Patch(&ViewPatch{Props: patchProps})
|
||
|
|
require.NotNil(t, v.Props)
|
||
|
|
|
||
|
|
(*patchProps)["key"] = "mutated"
|
||
|
|
assert.Equal(t, "value", v.Props["key"], "view Props must not be affected by patch mutation")
|
||
|
|
})
|
||
|
|
}
|