add channels info filters to selectors (#4093)

Adds groups channel message filters to group selectors. Includes scopes for message creation time, last response time, and message created by.

---

#### Does this PR need a docs update or release note?

- [x]  No

#### Type of change

- [x] 🌻 Feature

#### Issue(s)

* #3989

#### Test Plan

- [x]  Unit test
- [x] 💚 E2E
This commit is contained in:
Keepers 2023-08-25 12:09:20 -06:00 committed by GitHub
parent bf29443ad4
commit e96c21d342
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 430 additions and 285 deletions

View File

@ -49,7 +49,7 @@ type GroupsInfo struct {
// Channels Specific
ChannelName string `json:"channelName,omitempty"`
ChannelID string `json:"channelID,omitempty"`
LastResponseAt time.Time `json:"lastResponseAt,omitempty"`
LastReplyAt time.Time `json:"lastResponseAt,omitempty"`
MessageCreator string `json:"messageCreator,omitempty"`
MessagePreview string `json:"messagePreview,omitempty"`
ReplyCount int `json:"replyCount,omitempty"`

View File

@ -335,7 +335,7 @@ func (s *exchange) AllData() []ExchangeScope {
}
// -------------------
// Info Factories
// ItemInfo Factories
// ContactName produces one or more exchange contact name info scopes.
// Matches any contact whose name contains the provided string.
@ -352,7 +352,7 @@ func (sr *ExchangeRestore) ContactName(senderID string) []ExchangeScope {
}
}
// EventSubject produces one or more exchange event subject info scopes.
// EventOrganizer produces one or more exchange event subject info scopes.
// Matches any event where the event subject contains one of the provided strings.
// If any slice contains selectors.Any, that slice is reduced to [selectors.Any]
// If any slice contains selectors.None, that slice is reduced to [selectors.None]

View File

@ -6,6 +6,7 @@ import (
"github.com/alcionai/clues"
"github.com/alcionai/corso/src/internal/common/dttm"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/backup/identity"
"github.com/alcionai/corso/src/pkg/fault"
@ -242,7 +243,7 @@ func (s *groups) Channel(channel string) []GroupsScope {
// If any slice contains selectors.Any, that slice is reduced to [selectors.Any]
// If any slice contains selectors.None, that slice is reduced to [selectors.None]
// If any slice is empty, it defaults to [selectors.None]
func (s *sharePoint) ChannelMessages(channels, messages []string, opts ...option) []GroupsScope {
func (s *groups) ChannelMessages(channels, messages []string, opts ...option) []GroupsScope {
var (
scopes = []GroupsScope{}
os = append([]option{pathComparator()}, opts...)
@ -309,7 +310,76 @@ func (s *groups) LibraryItems(libraries, items []string, opts ...option) []Group
// -------------------
// ItemInfo Factories
// TODO
// MessageCreator produces one or more groups channelMessage info scopes.
// Matches any channel message created by the specified user.
// If any slice contains selectors.Any, that slice is reduced to [selectors.Any]
// If any slice contains selectors.None, that slice is reduced to [selectors.None]
// If any slice is empty, it defaults to [selectors.None]
func (s *GroupsRestore) MessageCreator(creator string) []GroupsScope {
return []GroupsScope{
makeInfoScope[GroupsScope](
GroupsChannelMessage,
GroupsInfoChannelMessageCreator,
[]string{creator},
filters.In),
}
}
// MessageCreatedAfter produces a channel message created-after info scope.
// Matches any message where the creation time is after the timestring.
// If the input equals selectors.Any, the scope will match all times.
// If the input is empty or selectors.None, the scope will always fail comparisons.
func (s *GroupsRestore) MessageCreatedAfter(timeStrings string) []GroupsScope {
return []GroupsScope{
makeInfoScope[GroupsScope](
GroupsChannelMessage,
GroupsInfoChannelMessageCreatedAfter,
[]string{timeStrings},
filters.Less),
}
}
// MessageCreatedBefore produces a channel message created-before info scope.
// Matches any message where the creation time is after the timestring.
// If the input equals selectors.Any, the scope will match all times.
// If the input is empty or selectors.None, the scope will always fail comparisons.
func (s *GroupsRestore) MessageCreatedBefore(timeStrings string) []GroupsScope {
return []GroupsScope{
makeInfoScope[GroupsScope](
GroupsChannelMessage,
GroupsInfoChannelMessageCreatedBefore,
[]string{timeStrings},
filters.Greater),
}
}
// MessageLastReplyAfter produces a channel message last-response-after info scope.
// Matches any message where last response time is after the timestring.
// If the input equals selectors.Any, the scope will match all times.
// If the input is empty or selectors.None, the scope will always fail comparisons.
func (s *GroupsRestore) MessageLastReplyAfter(timeStrings string) []GroupsScope {
return []GroupsScope{
makeInfoScope[GroupsScope](
GroupsChannelMessage,
GroupsInfoChannelMessageLastReplyAfter,
[]string{timeStrings},
filters.Less),
}
}
// MessageLastReplyBefore produces a channel message last-response-before info scope.
// Matches any message where last response time is after the timestring.
// If the input equals selectors.Any, the scope will match all times.
// If the input is empty or selectors.None, the scope will always fail comparisons.
func (s *GroupsRestore) MessageLastReplyBefore(timeStrings string) []GroupsScope {
return []GroupsScope{
makeInfoScope[GroupsScope](
GroupsChannelMessage,
GroupsInfoChannelMessageLastReplyBefore,
[]string{timeStrings},
filters.Greater),
}
}
// ---------------------------------------------------------------------------
// Categories
@ -334,9 +404,16 @@ const (
// details.itemInfo comparables
// channel drive selection
// channel and drive selection
GroupsInfoSiteLibraryDrive groupsCategory = "GroupsInfoSiteLibraryDrive"
GroupsInfoChannel groupsCategory = "GroupsInfoChannel"
// data contained within details.ItemInfo
GroupsInfoChannelMessageCreatedAfter groupsCategory = "GroupsInfoChannelMessageCreatedAfter"
GroupsInfoChannelMessageCreatedBefore groupsCategory = "GroupsInfoChannelMessageCreatedBefore"
GroupsInfoChannelMessageCreator groupsCategory = "GroupsInfoChannelMessageCreator"
GroupsInfoChannelMessageLastReplyAfter groupsCategory = "GroupsInfoChannelMessageLastReplyAfter"
GroupsInfoChannelMessageLastReplyBefore groupsCategory = "GroupsInfoChannelMessageLastReplyBefore"
)
// groupsLeafProperties describes common metadata of the leaf categories
@ -368,7 +445,9 @@ func (c groupsCategory) leafCat() categorizer {
switch c {
// TODO: if channels ever contain more than one type of item,
// we'll need to fix this up.
case GroupsChannel, GroupsChannelMessage:
case GroupsChannel, GroupsChannelMessage,
GroupsInfoChannelMessageCreatedAfter, GroupsInfoChannelMessageCreatedBefore, GroupsInfoChannelMessageCreator,
GroupsInfoChannelMessageLastReplyAfter, GroupsInfoChannelMessageLastReplyBefore:
return GroupsChannelMessage
case GroupsLibraryFolder, GroupsLibraryItem, GroupsInfoSiteLibraryDrive:
return GroupsLibraryItem
@ -414,15 +493,15 @@ func (c groupsCategory) pathValues(
rFld string
)
if ent.Groups == nil {
return nil, clues.New("no Groups ItemInfo in details")
}
switch c {
case GroupsChannel, GroupsChannelMessage:
folderCat, itemCat = GroupsChannel, GroupsChannelMessage
rFld = ent.Groups.ParentPath
case GroupsLibraryFolder, GroupsLibraryItem:
if ent.Groups == nil {
return nil, clues.New("no Groups ItemInfo in details")
}
folderCat, itemCat = GroupsLibraryFolder, GroupsLibraryItem
rFld = ent.Groups.ParentPath
default:
@ -591,8 +670,23 @@ func (s GroupsScope) matchesInfo(dii details.ItemInfo) bool {
return matchesAny(s, GroupsInfoSiteLibraryDrive, ds)
case GroupsInfoChannel:
ds := Any()
ds := []string{}
if len(info.ChannelID) > 0 {
ds = append(ds, info.ChannelID)
}
if len(info.ChannelName) > 0 {
ds = append(ds, info.ChannelName)
}
return matchesAny(s, GroupsInfoChannel, ds)
case GroupsInfoChannelMessageCreator:
i = info.MessageCreator
case GroupsInfoChannelMessageCreatedAfter, GroupsInfoChannelMessageCreatedBefore:
i = dttm.Format(info.Created)
case GroupsInfoChannelMessageLastReplyAfter, GroupsInfoChannelMessageLastReplyBefore:
i = dttm.Format(info.LastReplyAt)
}
return s.Matches(infoCat, i)

View File

@ -1,15 +1,21 @@
package selectors
import (
"strings"
"testing"
"time"
"github.com/alcionai/clues"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"golang.org/x/exp/slices"
"github.com/alcionai/corso/src/internal/common/dttm"
odConsts "github.com/alcionai/corso/src/internal/m365/service/onedrive/consts"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/path"
)
@ -55,211 +61,236 @@ func (suite *GroupsSelectorSuite) TestToGroupsRestore() {
assert.NotZero(t, or.Scopes())
}
// TODO(rkeepers): implement
// func (suite *GroupsSelectorSuite) TestGroupsRestore_Reduce() {
// toRR := func(cat path.CategoryType, siteID string, folders []string, item string) string {
// folderElems := make([]string, 0, len(folders))
func (suite *GroupsSelectorSuite) TestGroupsRestore_Reduce() {
toRR := func(cat path.CategoryType, midID string, folders []string, item string) string {
var (
folderElems = make([]string, 0, len(folders))
isDrive = cat == path.LibrariesCategory
)
// for _, f := range folders {
// folderElems = append(folderElems, f+".d")
// }
for _, f := range folders {
if isDrive {
f = f + ".d"
}
// return stubRepoRef(
// path.GroupsService,
// cat,
// siteID,
// strings.Join(folderElems, "/"),
// item)
// }
folderElems = append(folderElems, f)
}
// var (
// prefixElems = []string{
// odConsts.DrivesPathDir,
// "drive!id",
// odConsts.RootPathDir,
// }
// itemElems1 = []string{"folderA", "folderB"}
// itemElems2 = []string{"folderA", "folderC"}
// itemElems3 = []string{"folderD", "folderE"}
// pairAC = "folderA/folderC"
// pairGH = "folderG/folderH"
// item = toRR(
// path.LibrariesCategory,
// "sid",
// append(slices.Clone(prefixElems), itemElems1...),
// "item")
// item2 = toRR(
// path.LibrariesCategory,
// "sid",
// append(slices.Clone(prefixElems), itemElems2...),
// "item2")
// item3 = toRR(
// path.LibrariesCategory,
// "sid",
// append(slices.Clone(prefixElems), itemElems3...),
// "item3")
// item4 = stubRepoRef(path.GroupsService, path.PagesCategory, "sid", pairGH, "item4")
// item5 = stubRepoRef(path.GroupsService, path.PagesCategory, "sid", pairGH, "item5")
// )
return stubRepoRef(
path.GroupsService,
cat,
midID,
strings.Join(folderElems, "/"),
item)
}
// deets := &details.Details{
// DetailsModel: details.DetailsModel{
// Entries: []details.Entry{
// {
// RepoRef: item,
// ItemRef: "item",
// LocationRef: strings.Join(append([]string{odConsts.RootPathDir}, itemElems1...), "/"),
// ItemInfo: details.ItemInfo{
// Groups: &details.GroupsInfo{
// ItemType: details.GroupsLibrary,
// ItemName: "itemName",
// ParentPath: strings.Join(itemElems1, "/"),
// },
// },
// },
// {
// RepoRef: item2,
// LocationRef: strings.Join(append([]string{odConsts.RootPathDir}, itemElems2...), "/"),
// // ItemRef intentionally blank to test fallback case
// ItemInfo: details.ItemInfo{
// Groups: &details.GroupsInfo{
// ItemType: details.GroupsLibrary,
// ItemName: "itemName2",
// ParentPath: strings.Join(itemElems2, "/"),
// },
// },
// },
// {
// RepoRef: item3,
// ItemRef: "item3",
// LocationRef: strings.Join(append([]string{odConsts.RootPathDir}, itemElems3...), "/"),
// ItemInfo: details.ItemInfo{
// Groups: &details.GroupsInfo{
// ItemType: details.GroupsLibrary,
// ItemName: "itemName3",
// ParentPath: strings.Join(itemElems3, "/"),
// },
// },
// },
// {
// RepoRef: item4,
// LocationRef: pairGH,
// ItemRef: "item4",
// ItemInfo: details.ItemInfo{
// Groups: &details.GroupsInfo{
// ItemType: details.GroupsPage,
// ItemName: "itemName4",
// ParentPath: pairGH,
// },
// },
// },
// {
// RepoRef: item5,
// LocationRef: pairGH,
// // ItemRef intentionally blank to test fallback case
// ItemInfo: details.ItemInfo{
// Groups: &details.GroupsInfo{
// ItemType: details.GroupsPage,
// ItemName: "itemName5",
// ParentPath: pairGH,
// },
// },
// },
// },
// },
// }
var (
drivePrefixElems = []string{
odConsts.DrivesPathDir,
"drive!id",
odConsts.RootPathDir,
}
itemElems1 = []string{"folderA", "folderB"}
itemElems2 = []string{"folderA", "folderC"}
itemElems3 = []string{"folderD", "folderE"}
pairAC = "folderA/folderC"
libItem = toRR(
path.LibrariesCategory,
"sid",
append(slices.Clone(drivePrefixElems), itemElems1...),
"item")
libItem2 = toRR(
path.LibrariesCategory,
"sid",
append(slices.Clone(drivePrefixElems), itemElems2...),
"item2")
libItem3 = toRR(
path.LibrariesCategory,
"sid",
append(slices.Clone(drivePrefixElems), itemElems3...),
"item3")
chanItem = toRR(path.ChannelMessagesCategory, "gid", slices.Clone(itemElems1), "chitem")
chanItem2 = toRR(path.ChannelMessagesCategory, "gid", slices.Clone(itemElems2), "chitem2")
chanItem3 = toRR(path.ChannelMessagesCategory, "gid", slices.Clone(itemElems3), "chitem3")
)
// arr := func(s ...string) []string {
// return s
// }
deets := &details.Details{
DetailsModel: details.DetailsModel{
Entries: []details.Entry{
{
RepoRef: libItem,
ItemRef: "item",
LocationRef: strings.Join(append([]string{odConsts.RootPathDir}, itemElems1...), "/"),
ItemInfo: details.ItemInfo{
Groups: &details.GroupsInfo{
ItemType: details.SharePointLibrary,
ItemName: "itemName",
ParentPath: strings.Join(itemElems1, "/"),
},
},
},
{
RepoRef: libItem2,
LocationRef: strings.Join(append([]string{odConsts.RootPathDir}, itemElems2...), "/"),
// ItemRef intentionally blank to test fallback case
ItemInfo: details.ItemInfo{
Groups: &details.GroupsInfo{
ItemType: details.SharePointLibrary,
ItemName: "itemName2",
ParentPath: strings.Join(itemElems2, "/"),
},
},
},
{
RepoRef: libItem3,
ItemRef: "item3",
LocationRef: strings.Join(append([]string{odConsts.RootPathDir}, itemElems3...), "/"),
ItemInfo: details.ItemInfo{
Groups: &details.GroupsInfo{
ItemType: details.SharePointLibrary,
ItemName: "itemName3",
ParentPath: strings.Join(itemElems3, "/"),
},
},
},
{
RepoRef: chanItem,
ItemRef: "citem",
LocationRef: strings.Join(itemElems1, "/"),
ItemInfo: details.ItemInfo{
Groups: &details.GroupsInfo{
ItemType: details.TeamsChannelMessage,
ParentPath: strings.Join(itemElems1, "/"),
},
},
},
{
RepoRef: chanItem2,
LocationRef: strings.Join(itemElems2, "/"),
// ItemRef intentionally blank to test fallback case
ItemInfo: details.ItemInfo{
Groups: &details.GroupsInfo{
ItemType: details.TeamsChannelMessage,
ParentPath: strings.Join(itemElems2, "/"),
},
},
},
{
RepoRef: chanItem3,
ItemRef: "citem3",
LocationRef: strings.Join(itemElems3, "/"),
ItemInfo: details.ItemInfo{
Groups: &details.GroupsInfo{
ItemType: details.TeamsChannelMessage,
ParentPath: strings.Join(itemElems3, "/"),
},
},
},
},
},
}
// table := []struct {
// name string
// makeSelector func() *GroupsRestore
// expect []string
// cfg Config
// }{
// {
// name: "all",
// makeSelector: func() *GroupsRestore {
// odr := NewGroupsRestore(Any())
// odr.Include(odr.AllData())
// return odr
// },
// expect: arr(item, item2, item3, item4, item5),
// },
// {
// name: "only match item",
// makeSelector: func() *GroupsRestore {
// odr := NewGroupsRestore(Any())
// odr.Include(odr.LibraryItems(Any(), []string{"item2"}))
// return odr
// },
// expect: arr(item2),
// },
// {
// name: "id doesn't match name",
// makeSelector: func() *GroupsRestore {
// odr := NewGroupsRestore(Any())
// odr.Include(odr.LibraryItems(Any(), []string{"item2"}))
// return odr
// },
// expect: []string{},
// cfg: Config{OnlyMatchItemNames: true},
// },
// {
// name: "only match item name",
// makeSelector: func() *GroupsRestore {
// odr := NewGroupsRestore(Any())
// odr.Include(odr.LibraryItems(Any(), []string{"itemName2"}))
// return odr
// },
// expect: arr(item2),
// cfg: Config{OnlyMatchItemNames: true},
// },
// {
// name: "name doesn't match",
// makeSelector: func() *GroupsRestore {
// odr := NewGroupsRestore(Any())
// odr.Include(odr.LibraryItems(Any(), []string{"itemName2"}))
// return odr
// },
// expect: []string{},
// },
// {
// name: "only match folder",
// makeSelector: func() *GroupsRestore {
// odr := NewGroupsRestore([]string{"sid"})
// odr.Include(odr.LibraryFolders([]string{"folderA/folderB", pairAC}))
// return odr
// },
// expect: arr(item, item2),
// },
// {
// name: "pages match folder",
// makeSelector: func() *GroupsRestore {
// odr := NewGroupsRestore([]string{"sid"})
// odr.Include(odr.Pages([]string{pairGH, pairAC}))
// return odr
// },
// expect: arr(item4, item5),
// },
// }
// for _, test := range table {
// suite.Run(test.name, func() {
// t := suite.T()
arr := func(s ...string) []string {
return s
}
// ctx, flush := tester.NewContext(t)
// defer flush()
table := []struct {
name string
makeSelector func() *GroupsRestore
expect []string
cfg Config
}{
{
name: "all",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore(Any())
sel.Include(sel.AllData())
return sel
},
expect: arr(libItem, libItem2, libItem3, chanItem, chanItem2, chanItem3),
},
{
name: "only match library item",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore(Any())
sel.Include(sel.LibraryItems(Any(), []string{"item2"}))
return sel
},
expect: arr(libItem2),
},
{
name: "only match channel item",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore(Any())
sel.Include(sel.ChannelMessages(Any(), []string{"chitem2"}))
return sel
},
expect: arr(chanItem2),
},
{
name: "library id doesn't match name",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore(Any())
sel.Include(sel.LibraryItems(Any(), []string{"item2"}))
return sel
},
expect: []string{},
cfg: Config{OnlyMatchItemNames: true},
},
{
name: "channel id doesn't match name",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore(Any())
sel.Include(sel.ChannelMessages(Any(), []string{"item2"}))
return sel
},
expect: []string{},
cfg: Config{OnlyMatchItemNames: true},
},
{
name: "library only match item name",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore(Any())
sel.Include(sel.LibraryItems(Any(), []string{"itemName2"}))
return sel
},
expect: arr(libItem2),
cfg: Config{OnlyMatchItemNames: true},
},
{
name: "name doesn't match",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore(Any())
sel.Include(sel.LibraryItems(Any(), []string{"itemName2"}))
return sel
},
expect: []string{},
},
{
name: "only match folder",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore([]string{"sid"})
sel.Include(sel.LibraryFolders([]string{"folderA/folderB", pairAC}))
return sel
},
expect: arr(libItem, libItem2),
},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
// sel := test.makeSelector()
// sel.Configure(test.cfg)
// results := sel.Reduce(ctx, deets, fault.New(true))
// paths := results.Paths()
// assert.Equal(t, test.expect, paths)
// })
// }
// }
ctx, flush := tester.NewContext(t)
defer flush()
sel := test.makeSelector()
sel.Configure(test.cfg)
results := sel.Reduce(ctx, deets, fault.New(true))
paths := results.Paths()
assert.Equal(t, test.expect, paths)
})
}
}
func (suite *GroupsSelectorSuite) TestGroupsCategory_PathValues() {
var (
@ -324,25 +355,28 @@ func (suite *GroupsSelectorSuite) TestGroupsCategory_PathValues() {
}
}
// TODO(abin): implement
// func (suite *GroupsSelectorSuite) TestGroupsScope_MatchesInfo() {
// var (
// sel = NewGroupsRestore(Any())
// host = "www.website.com"
func (suite *GroupsSelectorSuite) TestGroupsScope_MatchesInfo() {
var (
sel = NewGroupsRestore(Any())
user = "user@mail.com"
host = "www.website.com"
// pth = "/foo"
// url = host + pth
// epoch = time.Time{}
// now = time.Now()
// modification = now.Add(15 * time.Minute)
// future = now.Add(45 * time.Minute)
// )
epoch = time.Time{}
now = time.Now()
modification = now.Add(15 * time.Minute)
future = now.Add(45 * time.Minute)
dtch = details.TeamsChannelMessage
)
// table := []struct {
// name string
// infoURL string
// scope []GroupsScope
// expect assert.BoolAssertionFunc
// }{
table := []struct {
name string
itemType details.ItemType
creator string
scope []GroupsScope
expect assert.BoolAssertionFunc
}{
// TODO(abin): implement
// {"host match", host, sel.WebURL([]string{host}), assert.True},
// {"url match", url, sel.WebURL([]string{url}), assert.True},
// {"host suffixes host", host, sel.WebURL([]string{host}, SuffixMatch()), assert.True},
@ -368,47 +402,64 @@ func (suite *GroupsSelectorSuite) TestGroupsCategory_PathValues() {
// {"not in library", host, sel.Library("not-included-library"), assert.False},
// {"library id", host, sel.Library("1234"), assert.True},
// {"not library id", host, sel.Library("abcd"), assert.False},
// }
// for _, test := range table {
// suite.Run(test.name, func() {
// t := suite.T()
// itemInfo := details.ItemInfo{
// Groups: &details.GroupsInfo{
// ItemType: details.GroupsPage,
// WebURL: test.infoURL,
// Created: now,
// Modified: modification,
// DriveName: "included-library",
// DriveID: "1234",
// },
// }
{"channel message created by", dtch, user, sel.MessageCreator(user), assert.True},
{"channel message not created by", dtch, user, sel.MessageCreator(host), assert.False},
{"chan msg create after the epoch", dtch, user, sel.MessageCreatedAfter(dttm.Format(epoch)), assert.True},
{"chan msg create after now", dtch, user, sel.MessageCreatedAfter(dttm.Format(now)), assert.False},
{"chan msg create after later", dtch, user, sel.MessageCreatedAfter(dttm.Format(future)), assert.False},
{"chan msg create before future", dtch, user, sel.MessageCreatedBefore(dttm.Format(future)), assert.True},
{"chan msg create before now", dtch, user, sel.MessageCreatedBefore(dttm.Format(now)), assert.False},
{"chan msg create before reply", dtch, user, sel.MessageCreatedBefore(dttm.Format(modification)), assert.True},
{"chan msg create before epoch", dtch, user, sel.MessageCreatedBefore(dttm.Format(now)), assert.False},
{"chan msg last reply after the epoch", dtch, user, sel.MessageLastReplyAfter(dttm.Format(epoch)), assert.True},
{"chan msg last reply after now", dtch, user, sel.MessageLastReplyAfter(dttm.Format(now)), assert.True},
{"chan msg last reply after later", dtch, user, sel.MessageLastReplyAfter(dttm.Format(future)), assert.False},
{"chan msg last reply before future", dtch, user, sel.MessageLastReplyBefore(dttm.Format(future)), assert.True},
{"chan msg last reply before now", dtch, user, sel.MessageLastReplyBefore(dttm.Format(now)), assert.False},
{"chan msg last reply before epoch", dtch, user, sel.MessageLastReplyBefore(dttm.Format(now)), assert.False},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
// scopes := setScopesToDefault(test.scope)
// for _, scope := range scopes {
// test.expect(t, scope.matchesInfo(itemInfo))
// }
// })
// }
// }
itemInfo := details.ItemInfo{
Groups: &details.GroupsInfo{
ItemType: test.itemType,
WebURL: test.creator,
MessageCreator: test.creator,
Created: now,
Modified: modification,
LastReplyAt: modification,
DriveName: "included-library",
DriveID: "1234",
},
}
scopes := setScopesToDefault(test.scope)
for _, scope := range scopes {
test.expect(t, scope.matchesInfo(itemInfo))
}
})
}
}
func (suite *GroupsSelectorSuite) TestCategory_PathType() {
table := []struct {
cat groupsCategory
pathType path.CategoryType
}{
{
cat: GroupsCategoryUnknown,
pathType: path.UnknownCategory,
},
{
cat: GroupsChannel,
pathType: path.ChannelMessagesCategory,
},
{
cat: GroupsChannelMessage,
pathType: path.ChannelMessagesCategory,
},
{GroupsCategoryUnknown, path.UnknownCategory},
{GroupsChannel, path.ChannelMessagesCategory},
{GroupsChannelMessage, path.ChannelMessagesCategory},
{GroupsInfoChannelMessageCreator, path.ChannelMessagesCategory},
{GroupsInfoChannelMessageCreatedAfter, path.ChannelMessagesCategory},
{GroupsInfoChannelMessageCreatedBefore, path.ChannelMessagesCategory},
{GroupsInfoChannelMessageLastReplyAfter, path.ChannelMessagesCategory},
{GroupsInfoChannelMessageLastReplyBefore, path.ChannelMessagesCategory},
{GroupsLibraryFolder, path.LibrariesCategory},
{GroupsLibraryItem, path.LibrariesCategory},
{GroupsInfoSiteLibraryDrive, path.LibrariesCategory},
}
for _, test := range table {
suite.Run(test.cat.String(), func() {