add teams chats selectors boilerplate
standard boilerplate additions, largely copy-paste and renamed from other files.
This commit is contained in:
parent
07997b0987
commit
0a6355eeb1
@ -591,7 +591,7 @@ func (ec exchangeCategory) isLeaf() bool {
|
||||
// pathValues transforms the two paths to maps of identified properties.
|
||||
//
|
||||
// Example:
|
||||
// [tenantID, service, userPN, category, mailFolder, mailID]
|
||||
// [tenantID, service, userID, category, mailFolder, mailID]
|
||||
// => {exchMailFolder: mailFolder, exchMail: mailID}
|
||||
func (ec exchangeCategory) pathValues(
|
||||
repo path.Path,
|
||||
@ -772,7 +772,7 @@ func (s ExchangeScope) matchesInfo(dii details.ItemInfo) bool {
|
||||
|
||||
infoCat := s.InfoCategory()
|
||||
|
||||
cfpc := categoryFromItemType(info.ItemType)
|
||||
cfpc := exchangeCategoryFromItemType(info.ItemType)
|
||||
if !typeAndCategoryMatches(infoCat, cfpc) {
|
||||
return false
|
||||
}
|
||||
@ -801,10 +801,10 @@ func (s ExchangeScope) matchesInfo(dii details.ItemInfo) bool {
|
||||
return s.Matches(infoCat, i)
|
||||
}
|
||||
|
||||
// categoryFromItemType interprets the category represented by the ExchangeInfo
|
||||
// exchangeCategoryFromItemType interprets the category represented by the ExchangeInfo
|
||||
// struct. Since every ExchangeInfo can hold all exchange data info, the exact
|
||||
// type that the struct represents must be compared using its ItemType prop.
|
||||
func categoryFromItemType(pct details.ItemType) exchangeCategory {
|
||||
func exchangeCategoryFromItemType(pct details.ItemType) exchangeCategory {
|
||||
switch pct {
|
||||
case details.ExchangeContact:
|
||||
return ExchangeContact
|
||||
|
||||
@ -1602,7 +1602,7 @@ func (suite *ExchangeSelectorSuite) TestCategoryFromItemType() {
|
||||
suite.Run(test.name, func() {
|
||||
t := suite.T()
|
||||
|
||||
result := categoryFromItemType(test.input)
|
||||
result := exchangeCategoryFromItemType(test.input)
|
||||
assert.Equal(t, test.expect, result)
|
||||
})
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ const (
|
||||
ServiceOneDrive service = 2 // OneDrive
|
||||
ServiceSharePoint service = 3 // SharePoint
|
||||
ServiceGroups service = 4 // Groups
|
||||
ServiceTeamsChats service = 5 // TeamsChats
|
||||
)
|
||||
|
||||
var serviceToPathType = map[service]path.ServiceType{
|
||||
@ -34,6 +35,7 @@ var serviceToPathType = map[service]path.ServiceType{
|
||||
ServiceOneDrive: path.OneDriveService,
|
||||
ServiceSharePoint: path.SharePointService,
|
||||
ServiceGroups: path.GroupsService,
|
||||
ServiceTeamsChats: path.TeamsChatsService,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
524
src/pkg/selectors/teamsChats.go
Normal file
524
src/pkg/selectors/teamsChats.go
Normal file
@ -0,0 +1,524 @@
|
||||
package selectors
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/alcionai/clues"
|
||||
|
||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||
"github.com/alcionai/corso/src/pkg/backup/identity"
|
||||
"github.com/alcionai/corso/src/pkg/fault"
|
||||
"github.com/alcionai/corso/src/pkg/filters"
|
||||
"github.com/alcionai/corso/src/pkg/path"
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Selectors
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type (
|
||||
// teamsChats provides an api for selecting
|
||||
// data scopes applicable to the TeamsChats service.
|
||||
teamsChats struct {
|
||||
Selector
|
||||
}
|
||||
|
||||
// TeamsChatsBackup provides an api for selecting
|
||||
// data scopes applicable to the TeamsChats service,
|
||||
// plus backup-specific methods.
|
||||
TeamsChatsBackup struct {
|
||||
teamsChats
|
||||
}
|
||||
|
||||
// TeamsChatsRestore provides an api for selecting
|
||||
// data scopes applicable to the TeamsChats service,
|
||||
// plus restore-specific methods.
|
||||
TeamsChatsRestore struct {
|
||||
teamsChats
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
_ Reducer = &TeamsChatsRestore{}
|
||||
_ pathCategorier = &TeamsChatsRestore{}
|
||||
_ reasoner = &TeamsChatsRestore{}
|
||||
)
|
||||
|
||||
// NewTeamsChats produces a new Selector with the service set to ServiceTeamsChats.
|
||||
func NewTeamsChatsBackup(users []string) *TeamsChatsBackup {
|
||||
src := TeamsChatsBackup{
|
||||
teamsChats{
|
||||
newSelector(ServiceTeamsChats, users),
|
||||
},
|
||||
}
|
||||
|
||||
return &src
|
||||
}
|
||||
|
||||
// ToTeamsChatsBackup transforms the generic selector into an TeamsChatsBackup.
|
||||
// Errors if the service defined by the selector is not ServiceTeamsChats.
|
||||
func (s Selector) ToTeamsChatsBackup() (*TeamsChatsBackup, error) {
|
||||
if s.Service != ServiceTeamsChats {
|
||||
return nil, badCastErr(ServiceTeamsChats, s.Service)
|
||||
}
|
||||
|
||||
src := TeamsChatsBackup{teamsChats{s}}
|
||||
|
||||
return &src, nil
|
||||
}
|
||||
|
||||
func (s TeamsChatsBackup) SplitByResourceOwner(users []string) []TeamsChatsBackup {
|
||||
sels := splitByProtectedResource[TeamsChatsScope](s.Selector, users, TeamsChatsUser)
|
||||
|
||||
ss := make([]TeamsChatsBackup, 0, len(sels))
|
||||
for _, sel := range sels {
|
||||
ss = append(ss, TeamsChatsBackup{teamsChats{sel}})
|
||||
}
|
||||
|
||||
return ss
|
||||
}
|
||||
|
||||
// NewTeamsChatsRestore produces a new Selector with the service set to ServiceTeamsChats.
|
||||
func NewTeamsChatsRestore(users []string) *TeamsChatsRestore {
|
||||
src := TeamsChatsRestore{
|
||||
teamsChats{
|
||||
newSelector(ServiceTeamsChats, users),
|
||||
},
|
||||
}
|
||||
|
||||
return &src
|
||||
}
|
||||
|
||||
// ToTeamsChatsRestore transforms the generic selector into an TeamsChatsRestore.
|
||||
// Errors if the service defined by the selector is not ServiceTeamsChats.
|
||||
func (s Selector) ToTeamsChatsRestore() (*TeamsChatsRestore, error) {
|
||||
if s.Service != ServiceTeamsChats {
|
||||
return nil, badCastErr(ServiceTeamsChats, s.Service)
|
||||
}
|
||||
|
||||
src := TeamsChatsRestore{teamsChats{s}}
|
||||
|
||||
return &src, nil
|
||||
}
|
||||
|
||||
func (sr TeamsChatsRestore) SplitByResourceOwner(users []string) []TeamsChatsRestore {
|
||||
sels := splitByProtectedResource[TeamsChatsScope](sr.Selector, users, TeamsChatsUser)
|
||||
|
||||
ss := make([]TeamsChatsRestore, 0, len(sels))
|
||||
for _, sel := range sels {
|
||||
ss = append(ss, TeamsChatsRestore{teamsChats{sel}})
|
||||
}
|
||||
|
||||
return ss
|
||||
}
|
||||
|
||||
// PathCategories produces the aggregation of discrete users described by each type of scope.
|
||||
func (s teamsChats) PathCategories() selectorPathCategories {
|
||||
return selectorPathCategories{
|
||||
Excludes: pathCategoriesIn[TeamsChatsScope, teamsChatsCategory](s.Excludes),
|
||||
Filters: pathCategoriesIn[TeamsChatsScope, teamsChatsCategory](s.Filters),
|
||||
Includes: pathCategoriesIn[TeamsChatsScope, teamsChatsCategory](s.Includes),
|
||||
}
|
||||
}
|
||||
|
||||
// Reasons returns a deduplicated set of the backup reasons produced
|
||||
// using the selector's discrete owner and each scopes' service and
|
||||
// category types.
|
||||
func (s teamsChats) Reasons(tenantID string, useOwnerNameForID bool) []identity.Reasoner {
|
||||
return reasonsFor(s, tenantID, useOwnerNameForID)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Stringers and Concealers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func (s TeamsChatsScope) Conceal() string { return conceal(s) }
|
||||
func (s TeamsChatsScope) Format(fs fmt.State, r rune) { format(s, fs, r) }
|
||||
func (s TeamsChatsScope) String() string { return conceal(s) }
|
||||
func (s TeamsChatsScope) PlainString() string { return plainString(s) }
|
||||
|
||||
// -------------------
|
||||
// Exclude/Includes
|
||||
|
||||
// Exclude appends the provided scopes to the selector's exclusion set.
|
||||
// Every Exclusion scope applies globally, affecting all inclusion scopes.
|
||||
// Data is excluded if it matches ANY exclusion (of the same data category).
|
||||
//
|
||||
// All parts of the scope must match for data to be exclucded.
|
||||
// Ex: Mail(u1, f1, m1) => only excludes mail if it is owned by user u1,
|
||||
// located in folder f1, and ID'd as m1. MailSender(foo) => only excludes
|
||||
// mail whose sender is foo. Use selectors.Any() to wildcard a scope value.
|
||||
// No value will match if selectors.None() is provided.
|
||||
//
|
||||
// Group-level scopes will automatically apply the Any() wildcard to
|
||||
// child properties.
|
||||
// ex: User(u1) automatically cascades to all chats,
|
||||
func (s *teamsChats) Exclude(scopes ...[]TeamsChatsScope) {
|
||||
s.Excludes = appendScopes(s.Excludes, scopes...)
|
||||
}
|
||||
|
||||
// Filter appends the provided scopes to the selector's filters set.
|
||||
// A selector with >0 filters and 0 inclusions will include any data
|
||||
// that passes all filters.
|
||||
// A selector with >0 filters and >0 inclusions will reduce the
|
||||
// inclusion set to only the data that passes all filters.
|
||||
// Data is retained if it passes ALL filters (of the same data category).
|
||||
//
|
||||
// All parts of the scope must match for data to pass the filter.
|
||||
// Ex: Mail(u1, f1, m1) => only passes mail that is owned by user u1,
|
||||
// located in folder f1, and ID'd as m1. MailSender(foo) => only passes
|
||||
// mail whose sender is foo. Use selectors.Any() to wildcard a scope value.
|
||||
// No value will match if selectors.None() is provided.
|
||||
//
|
||||
// Group-level scopes will automatically apply the Any() wildcard to
|
||||
// child properties.
|
||||
// ex: User(u1) automatically cascades to all chats,
|
||||
func (s *teamsChats) Filter(scopes ...[]TeamsChatsScope) {
|
||||
s.Filters = appendScopes(s.Filters, scopes...)
|
||||
}
|
||||
|
||||
// Include appends the provided scopes to the selector's inclusion set.
|
||||
// Data is included if it matches ANY inclusion.
|
||||
// The inclusion set is later filtered (all included data must pass ALL
|
||||
// filters) and excluded (all included data must not match ANY exclusion).
|
||||
// Data is included if it matches ANY inclusion (of the same data category).
|
||||
//
|
||||
// All parts of the scope must match for data to be included.
|
||||
// Ex: Mail(u1, f1, m1) => only includes mail if it is owned by user u1,
|
||||
// located in folder f1, and ID'd as m1. MailSender(foo) => only includes
|
||||
// mail whose sender is foo. Use selectors.Any() to wildcard a scope value.
|
||||
// No value will match if selectors.None() is provided.
|
||||
//
|
||||
// Group-level scopes will automatically apply the Any() wildcard to
|
||||
// child properties.
|
||||
// ex: User(u1) automatically cascades to all chats,
|
||||
func (s *teamsChats) Include(scopes ...[]TeamsChatsScope) {
|
||||
s.Includes = appendScopes(s.Includes, scopes...)
|
||||
}
|
||||
|
||||
// Scopes retrieves the list of teamsChatsScopes in the selector.
|
||||
func (s *teamsChats) Scopes() []TeamsChatsScope {
|
||||
return scopes[TeamsChatsScope](s.Selector)
|
||||
}
|
||||
|
||||
type TeamsChatsItemScopeConstructor func([]string, []string, ...option) []TeamsChatsScope
|
||||
|
||||
// -------------------
|
||||
// Scope Factories
|
||||
|
||||
// Chats produces one or more teamsChats scopes.
|
||||
// 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]
|
||||
// options are only applied to the folder scopes.
|
||||
func (s *teamsChats) Chats(chats []string, opts ...option) []TeamsChatsScope {
|
||||
scopes := []TeamsChatsScope{}
|
||||
|
||||
scopes = append(
|
||||
scopes,
|
||||
makeScope[TeamsChatsScope](TeamsChatsChat, chats, defaultItemOptions(s.Cfg)...))
|
||||
|
||||
return scopes
|
||||
}
|
||||
|
||||
// Retrieves all teamsChats data.
|
||||
// Each user id generates three scopes, one for each data type: contact, event, and mail.
|
||||
// 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 *teamsChats) AllData() []TeamsChatsScope {
|
||||
scopes := []TeamsChatsScope{}
|
||||
|
||||
scopes = append(scopes, makeScope[TeamsChatsScope](TeamsChatsChat, Any()))
|
||||
|
||||
return scopes
|
||||
}
|
||||
|
||||
// -------------------
|
||||
// ItemInfo Factories
|
||||
|
||||
// ChatMember produces one or more teamsChats chat member info scopes.
|
||||
// Matches any chat member whose email contains the provided string.
|
||||
// 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 (sr *TeamsChatsRestore) ChatMember(memberID string) []TeamsChatsScope {
|
||||
return []TeamsChatsScope{
|
||||
makeInfoScope[TeamsChatsScope](
|
||||
TeamsChatsChat,
|
||||
TeamsChatsInfoChatMember,
|
||||
[]string{memberID},
|
||||
filters.In),
|
||||
}
|
||||
}
|
||||
|
||||
// ChatName produces one or more teamsChats chat name info scopes.
|
||||
// Matches any chat whose name contains the provided string.
|
||||
// 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 (sr *TeamsChatsRestore) ChatName(memberID string) []TeamsChatsScope {
|
||||
return []TeamsChatsScope{
|
||||
makeInfoScope[TeamsChatsScope](
|
||||
TeamsChatsChat,
|
||||
TeamsChatsInfoChatName,
|
||||
[]string{memberID},
|
||||
filters.In),
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Categories
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// teamsChatsCategory enumerates the type of the lowest level
|
||||
// of data specified by the scope.
|
||||
type teamsChatsCategory string
|
||||
|
||||
// interface compliance checks
|
||||
var _ categorizer = TeamsChatsCategoryUnknown
|
||||
|
||||
const (
|
||||
TeamsChatsCategoryUnknown teamsChatsCategory = ""
|
||||
|
||||
// types of data identified by teamsChats
|
||||
TeamsChatsUser teamsChatsCategory = "TeamsChatsUser"
|
||||
TeamsChatsChat teamsChatsCategory = "TeamsChatsChat"
|
||||
|
||||
// data contained within details.ItemInfo
|
||||
TeamsChatsInfoChatMember teamsChatsCategory = "TeamsChatsInfoChatMember"
|
||||
TeamsChatsInfoChatName teamsChatsCategory = "TeamsChatsInfoChatName"
|
||||
)
|
||||
|
||||
// teamsChatsLeafProperties describes common metadata of the leaf categories
|
||||
var teamsChatsLeafProperties = map[categorizer]leafProperty{
|
||||
TeamsChatsChat: {
|
||||
pathKeys: []categorizer{TeamsChatsChat},
|
||||
pathType: path.ChatsCategory,
|
||||
},
|
||||
TeamsChatsUser: { // the root category must be represented, even though it isn't a leaf
|
||||
pathKeys: []categorizer{TeamsChatsUser},
|
||||
pathType: path.UnknownCategory,
|
||||
},
|
||||
}
|
||||
|
||||
func (ec teamsChatsCategory) String() string {
|
||||
return string(ec)
|
||||
}
|
||||
|
||||
// leafCat returns the leaf category of the receiver.
|
||||
// If the receiver category has multiple leaves (ex: User) or no leaves,
|
||||
// (ex: Unknown), the receiver itself is returned.
|
||||
// If the receiver category is an info type (ex: TeamsChatsInfoChatMember),
|
||||
// returns the category covered by the info.
|
||||
// Ex: TeamsChatsChatFolder.leafCat() => TeamsChatsChat
|
||||
// Ex: TeamsChatsUser.leafCat() => TeamsChatsUser
|
||||
func (ec teamsChatsCategory) leafCat() categorizer {
|
||||
switch ec {
|
||||
case TeamsChatsChat, TeamsChatsInfoChatMember, TeamsChatsInfoChatName:
|
||||
return TeamsChatsChat
|
||||
}
|
||||
|
||||
return ec
|
||||
}
|
||||
|
||||
// rootCat returns the root category type.
|
||||
func (ec teamsChatsCategory) rootCat() categorizer {
|
||||
return TeamsChatsUser
|
||||
}
|
||||
|
||||
// unknownCat returns the unknown category type.
|
||||
func (ec teamsChatsCategory) unknownCat() categorizer {
|
||||
return TeamsChatsCategoryUnknown
|
||||
}
|
||||
|
||||
// isUnion returns true if c is a user
|
||||
func (ec teamsChatsCategory) isUnion() bool {
|
||||
return ec == ec.rootCat()
|
||||
}
|
||||
|
||||
// isLeaf is true if the category is a mail, event, or contact category.
|
||||
func (ec teamsChatsCategory) isLeaf() bool {
|
||||
return ec == ec.leafCat()
|
||||
}
|
||||
|
||||
// pathValues transforms the two paths to maps of identified properties.
|
||||
//
|
||||
// Example:
|
||||
// [tenantID, service, userID, category, chatID]
|
||||
// => {teamsChat: chatID}
|
||||
func (ec teamsChatsCategory) pathValues(
|
||||
repo path.Path,
|
||||
ent details.Entry,
|
||||
cfg Config,
|
||||
) (map[categorizer][]string, error) {
|
||||
var itemCat categorizer
|
||||
|
||||
switch ec {
|
||||
case TeamsChatsChat:
|
||||
itemCat = TeamsChatsChat
|
||||
|
||||
default:
|
||||
return nil, clues.New("bad teamsChatCategory").With("category", ec)
|
||||
}
|
||||
|
||||
item := ent.ItemRef
|
||||
if len(item) == 0 {
|
||||
item = repo.Item()
|
||||
}
|
||||
|
||||
items := []string{ent.ShortRef, item}
|
||||
|
||||
// only include the item ID when the user is NOT matching
|
||||
// item names. TeamsChats data does not contain an item name,
|
||||
// only an ID, and we don't want to mix up the two.
|
||||
if cfg.OnlyMatchItemNames {
|
||||
items = []string{ent.ShortRef}
|
||||
}
|
||||
|
||||
result := map[categorizer][]string{
|
||||
itemCat: items,
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// pathKeys returns the path keys recognized by the receiver's leaf type.
|
||||
func (ec teamsChatsCategory) pathKeys() []categorizer {
|
||||
return teamsChatsLeafProperties[ec.leafCat()].pathKeys
|
||||
}
|
||||
|
||||
// PathType converts the category's leaf type into the matching path.CategoryType.
|
||||
func (ec teamsChatsCategory) PathType() path.CategoryType {
|
||||
return teamsChatsLeafProperties[ec.leafCat()].pathType
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Scopes
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// TeamsChatsScope specifies the data available
|
||||
// when interfacing with the TeamsChats service.
|
||||
type TeamsChatsScope scope
|
||||
|
||||
// interface compliance checks
|
||||
var _ scoper = &TeamsChatsScope{}
|
||||
|
||||
// Category describes the type of the data in scope.
|
||||
func (s TeamsChatsScope) Category() teamsChatsCategory {
|
||||
return teamsChatsCategory(getCategory(s))
|
||||
}
|
||||
|
||||
// categorizer type is a generic wrapper around Category.
|
||||
// Primarily used by scopes.go to for abstract comparisons.
|
||||
func (s TeamsChatsScope) categorizer() categorizer {
|
||||
return s.Category()
|
||||
}
|
||||
|
||||
// Matches returns true if the category is included in the scope's
|
||||
// data type, and the target string matches that category's comparator.
|
||||
func (s TeamsChatsScope) Matches(cat teamsChatsCategory, target string) bool {
|
||||
return matches(s, cat, target)
|
||||
}
|
||||
|
||||
// InfoCategory returns the category enum of the scope info.
|
||||
// If the scope is not an info type, returns TeamsChatsUnknownCategory.
|
||||
func (s TeamsChatsScope) InfoCategory() teamsChatsCategory {
|
||||
return teamsChatsCategory(getInfoCategory(s))
|
||||
}
|
||||
|
||||
// IncludeCategory checks whether the scope includes a certain category of data.
|
||||
// Ex: to check if the scope includes mail data:
|
||||
// s.IncludesCategory(selector.TeamsChatsMail)
|
||||
func (s TeamsChatsScope) IncludesCategory(cat teamsChatsCategory) bool {
|
||||
return categoryMatches(s.Category(), cat)
|
||||
}
|
||||
|
||||
// returns true if the category is included in the scope's data type,
|
||||
// and the value is set to Any().
|
||||
func (s TeamsChatsScope) IsAny(cat teamsChatsCategory) bool {
|
||||
return IsAnyTarget(s, cat)
|
||||
}
|
||||
|
||||
// Get returns the data category in the scope. If the scope
|
||||
// contains all data types for a user, it'll return the
|
||||
// TeamsChatsUser category.
|
||||
func (s TeamsChatsScope) Get(cat teamsChatsCategory) []string {
|
||||
return getCatValue(s, cat)
|
||||
}
|
||||
|
||||
// sets a value by category to the scope. Only intended for internal use.
|
||||
func (s TeamsChatsScope) set(cat teamsChatsCategory, v []string, opts ...option) TeamsChatsScope {
|
||||
return set(s, cat, v, opts...)
|
||||
}
|
||||
|
||||
// setDefaults ensures that contact folder, mail folder, and user category
|
||||
// scopes all express `AnyTgt` for their child category types.
|
||||
func (s TeamsChatsScope) setDefaults() {
|
||||
switch s.Category() {
|
||||
case TeamsChatsUser:
|
||||
s[TeamsChatsChat.String()] = passAny
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Backup Details Filtering
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Reduce filters the entries in a details struct to only those that match the
|
||||
// inclusions, filters, and exclusions in the selector.
|
||||
func (s teamsChats) Reduce(
|
||||
ctx context.Context,
|
||||
deets *details.Details,
|
||||
errs *fault.Bus,
|
||||
) *details.Details {
|
||||
return reduce[TeamsChatsScope](
|
||||
ctx,
|
||||
deets,
|
||||
s.Selector,
|
||||
map[path.CategoryType]teamsChatsCategory{
|
||||
path.ChatsCategory: TeamsChatsChat,
|
||||
},
|
||||
errs)
|
||||
}
|
||||
|
||||
// matchesInfo handles the standard behavior when comparing a scope and an TeamsChatsInfo
|
||||
// returns true if the scope and info match for the provided category.
|
||||
func (s TeamsChatsScope) matchesInfo(dii details.ItemInfo) bool {
|
||||
info := dii.TeamsChats
|
||||
if info == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
infoCat := s.InfoCategory()
|
||||
|
||||
cfpc := teamsChatsCategoryFromItemType(info.ItemType)
|
||||
if !typeAndCategoryMatches(infoCat, cfpc) {
|
||||
return false
|
||||
}
|
||||
|
||||
i := ""
|
||||
|
||||
switch infoCat {
|
||||
case TeamsChatsInfoChatMember:
|
||||
i = strings.Join(info.Chat.Members, ",")
|
||||
case TeamsChatsInfoChatName:
|
||||
i = info.Chat.Name
|
||||
}
|
||||
|
||||
return s.Matches(infoCat, i)
|
||||
}
|
||||
|
||||
// teamsChatsCategoryFromItemType interprets the category represented by the TeamsChatsInfo
|
||||
// struct. Since every TeamsChatsInfo can hold all teamsChats data info, the exact
|
||||
// type that the struct represents must be compared using its ItemType prop.
|
||||
func teamsChatsCategoryFromItemType(pct details.ItemType) teamsChatsCategory {
|
||||
switch pct {
|
||||
case details.TeamsChat:
|
||||
return TeamsChatsChat
|
||||
}
|
||||
|
||||
return TeamsChatsCategoryUnknown
|
||||
}
|
||||
843
src/pkg/selectors/teamsChats_test.go
Normal file
843
src/pkg/selectors/teamsChats_test.go
Normal file
@ -0,0 +1,843 @@
|
||||
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"
|
||||
|
||||
"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/filters"
|
||||
"github.com/alcionai/corso/src/pkg/path"
|
||||
)
|
||||
|
||||
type TeamsChatsSelectorSuite struct {
|
||||
tester.Suite
|
||||
}
|
||||
|
||||
func TestTeamsChatsSelectorSuite(t *testing.T) {
|
||||
suite.Run(t, &TeamsChatsSelectorSuite{Suite: tester.NewUnitSuite(t)})
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestNewTeamsChatsBackup() {
|
||||
t := suite.T()
|
||||
eb := NewTeamsChatsBackup(nil)
|
||||
assert.Equal(t, eb.Service, ServiceTeamsChats)
|
||||
assert.NotZero(t, eb.Scopes())
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestToTeamsChatsBackup() {
|
||||
t := suite.T()
|
||||
eb := NewTeamsChatsBackup(nil)
|
||||
s := eb.Selector
|
||||
eb, err := s.ToTeamsChatsBackup()
|
||||
require.NoError(t, err, clues.ToCore(err))
|
||||
assert.Equal(t, eb.Service, ServiceTeamsChats)
|
||||
assert.NotZero(t, eb.Scopes())
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestNewTeamsChatsRestore() {
|
||||
t := suite.T()
|
||||
er := NewTeamsChatsRestore(nil)
|
||||
assert.Equal(t, er.Service, ServiceTeamsChats)
|
||||
assert.NotZero(t, er.Scopes())
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestToTeamsChatsRestore() {
|
||||
t := suite.T()
|
||||
eb := NewTeamsChatsRestore(nil)
|
||||
s := eb.Selector
|
||||
eb, err := s.ToTeamsChatsRestore()
|
||||
require.NoError(t, err, clues.ToCore(err))
|
||||
assert.Equal(t, eb.Service, ServiceTeamsChats)
|
||||
assert.NotZero(t, eb.Scopes())
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsSelector_Exclude_TeamsChats() {
|
||||
t := suite.T()
|
||||
|
||||
const (
|
||||
user = "user"
|
||||
folder = AnyTgt
|
||||
c1 = "c1"
|
||||
c2 = "c2"
|
||||
)
|
||||
|
||||
sel := NewTeamsChatsBackup([]string{user})
|
||||
sel.Exclude(sel.Chats([]string{c1, c2}))
|
||||
scopes := sel.Excludes
|
||||
require.Len(t, scopes, 1)
|
||||
|
||||
scopeMustHave(
|
||||
t,
|
||||
TeamsChatsScope(scopes[0]),
|
||||
map[categorizer][]string{
|
||||
TeamsChatsChat: {c1, c2},
|
||||
})
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsSelector_Include_TeamsChats() {
|
||||
t := suite.T()
|
||||
|
||||
const (
|
||||
user = "user"
|
||||
folder = AnyTgt
|
||||
c1 = "c1"
|
||||
c2 = "c2"
|
||||
)
|
||||
|
||||
sel := NewTeamsChatsBackup([]string{user})
|
||||
sel.Include(sel.Chats([]string{c1, c2}))
|
||||
scopes := sel.Includes
|
||||
require.Len(t, scopes, 1)
|
||||
|
||||
scopeMustHave(
|
||||
t,
|
||||
TeamsChatsScope(scopes[0]),
|
||||
map[categorizer][]string{
|
||||
TeamsChatsChat: {c1, c2},
|
||||
})
|
||||
|
||||
assert.Equal(t, sel.Scopes()[0].Category(), TeamsChatsChat)
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsSelector_Exclude_AllData() {
|
||||
t := suite.T()
|
||||
|
||||
const (
|
||||
u1 = "u1"
|
||||
u2 = "u2"
|
||||
)
|
||||
|
||||
sel := NewTeamsChatsBackup([]string{u1, u2})
|
||||
sel.Exclude(sel.AllData())
|
||||
scopes := sel.Excludes
|
||||
require.Len(t, scopes, 1)
|
||||
|
||||
for _, sc := range scopes {
|
||||
if sc[scopeKeyCategory].Compare(TeamsChatsChat.String()) {
|
||||
scopeMustHave(
|
||||
t,
|
||||
TeamsChatsScope(sc),
|
||||
map[categorizer][]string{
|
||||
TeamsChatsChat: Any(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsSelector_Include_AllData() {
|
||||
t := suite.T()
|
||||
|
||||
const (
|
||||
u1 = "u1"
|
||||
u2 = "u2"
|
||||
)
|
||||
|
||||
sel := NewTeamsChatsBackup([]string{u1, u2})
|
||||
sel.Include(sel.AllData())
|
||||
scopes := sel.Includes
|
||||
require.Len(t, scopes, 1)
|
||||
|
||||
for _, sc := range scopes {
|
||||
if sc[scopeKeyCategory].Compare(TeamsChatsChat.String()) {
|
||||
scopeMustHave(
|
||||
t,
|
||||
TeamsChatsScope(sc),
|
||||
map[categorizer][]string{
|
||||
TeamsChatsChat: Any(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsBackup_Scopes() {
|
||||
eb := NewTeamsChatsBackup(Any())
|
||||
eb.Include(eb.AllData())
|
||||
|
||||
scopes := eb.Scopes()
|
||||
assert.Len(suite.T(), scopes, 1)
|
||||
|
||||
for _, sc := range scopes {
|
||||
cat := sc.Category()
|
||||
suite.Run(cat.String(), func() {
|
||||
t := suite.T()
|
||||
|
||||
switch sc.Category() {
|
||||
case TeamsChatsChat:
|
||||
assert.True(t, sc.IsAny(TeamsChatsChat))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsScope_Category() {
|
||||
table := []struct {
|
||||
is teamsChatsCategory
|
||||
expect teamsChatsCategory
|
||||
check assert.ComparisonAssertionFunc
|
||||
}{
|
||||
{TeamsChatsCategoryUnknown, TeamsChatsCategoryUnknown, assert.Equal},
|
||||
{TeamsChatsCategoryUnknown, TeamsChatsUser, assert.NotEqual},
|
||||
{TeamsChatsChat, TeamsChatsChat, assert.Equal},
|
||||
{TeamsChatsUser, TeamsChatsUser, assert.Equal},
|
||||
{TeamsChatsUser, TeamsChatsCategoryUnknown, assert.NotEqual},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(test.is.String()+test.expect.String(), func() {
|
||||
eb := NewTeamsChatsBackup(Any())
|
||||
eb.Includes = []scope{
|
||||
{scopeKeyCategory: filters.Identity(test.is.String())},
|
||||
}
|
||||
scope := eb.Scopes()[0]
|
||||
test.check(suite.T(), test.expect, scope.Category())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsScope_IncludesCategory() {
|
||||
table := []struct {
|
||||
is teamsChatsCategory
|
||||
expect teamsChatsCategory
|
||||
check assert.BoolAssertionFunc
|
||||
}{
|
||||
{TeamsChatsCategoryUnknown, TeamsChatsCategoryUnknown, assert.False},
|
||||
{TeamsChatsCategoryUnknown, TeamsChatsUser, assert.True},
|
||||
{TeamsChatsUser, TeamsChatsUser, assert.True},
|
||||
{TeamsChatsUser, TeamsChatsCategoryUnknown, assert.True},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(test.is.String()+test.expect.String(), func() {
|
||||
eb := NewTeamsChatsBackup(Any())
|
||||
eb.Includes = []scope{
|
||||
{scopeKeyCategory: filters.Identity(test.is.String())},
|
||||
}
|
||||
scope := eb.Scopes()[0]
|
||||
test.check(suite.T(), scope.IncludesCategory(test.expect))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsScope_Get() {
|
||||
eb := NewTeamsChatsBackup(Any())
|
||||
eb.Include(eb.AllData())
|
||||
|
||||
scopes := eb.Scopes()
|
||||
|
||||
table := []teamsChatsCategory{
|
||||
TeamsChatsChat,
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(test.String(), func() {
|
||||
t := suite.T()
|
||||
|
||||
for _, sc := range scopes {
|
||||
switch sc.Category() {
|
||||
case TeamsChatsChat:
|
||||
assert.Equal(t, Any(), sc.Get(TeamsChatsChat))
|
||||
}
|
||||
assert.Equal(t, None(), sc.Get(TeamsChatsCategoryUnknown))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsScope_MatchesInfo() {
|
||||
cs := NewTeamsChatsRestore(Any())
|
||||
|
||||
const (
|
||||
name = "smarf mcfnords"
|
||||
member = "cooks@2many.smarf"
|
||||
subject = "I have seen the fnords!"
|
||||
)
|
||||
|
||||
var (
|
||||
now = time.Now()
|
||||
future = now.Add(1 * time.Minute)
|
||||
)
|
||||
|
||||
infoWith := func(itype details.ItemType) details.ItemInfo {
|
||||
return details.ItemInfo{
|
||||
TeamsChats: &details.TeamsChatsInfo{
|
||||
ItemType: itype,
|
||||
Chat: details.ChatInfo{
|
||||
CreatedAt: now,
|
||||
HasExternalMembers: false,
|
||||
LastMessageAt: future,
|
||||
LastMessagePreview: "preview",
|
||||
Members: []string{member},
|
||||
MessageCount: 1,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
itype details.ItemType
|
||||
scope []TeamsChatsScope
|
||||
expect assert.BoolAssertionFunc
|
||||
}{
|
||||
{"chat with a different member", details.TeamsChat, cs.ChatMember("blarps"), assert.False},
|
||||
{"chat with the same member", details.TeamsChat, cs.ChatMember(member), assert.True},
|
||||
{"chat with a member submatch search", details.TeamsChat, cs.ChatMember(member[2:5]), assert.True},
|
||||
{"chat with a different name", details.TeamsChat, cs.ChatName("blarps"), assert.False},
|
||||
{"chat with the same name", details.TeamsChat, cs.ChatName(name), assert.True},
|
||||
{"chat with a subname search", details.TeamsChat, cs.ChatName(name[2:5]), assert.True},
|
||||
}
|
||||
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(infoWith(test.itype)))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsScope_MatchesPath() {
|
||||
const (
|
||||
user = "userID"
|
||||
chat = "chatID"
|
||||
)
|
||||
|
||||
repoRef, err := path.Build("tid", user, path.TeamsChatsService, path.ChatsCategory, true, chat)
|
||||
require.NoError(suite.T(), err, clues.ToCore(err))
|
||||
|
||||
var (
|
||||
loc = strings.Join([]string{chat}, "/")
|
||||
short = "thisisahashofsomekind"
|
||||
cs = NewTeamsChatsRestore(Any())
|
||||
ent = details.Entry{
|
||||
RepoRef: repoRef.String(),
|
||||
ShortRef: short,
|
||||
ItemRef: chat,
|
||||
LocationRef: loc,
|
||||
}
|
||||
)
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
scope []TeamsChatsScope
|
||||
shortRef string
|
||||
expect assert.BoolAssertionFunc
|
||||
}{
|
||||
{"all items", cs.AllData(), "", assert.True},
|
||||
{"all chats", cs.Chats(Any()), "", assert.True},
|
||||
{"no chats", cs.Chats(None()), "", assert.False},
|
||||
{"matching chats", cs.Chats([]string{chat}), "", assert.True},
|
||||
{"non-matching chats", cs.Chats([]string{"smarf"}), "", assert.False},
|
||||
{"one of multiple chats", cs.Chats([]string{"smarf", chat}), "", assert.True},
|
||||
{"chats short ref", cs.Chats([]string{short}), short, assert.True},
|
||||
{"non-leaf short ref", cs.Chats([]string{"foo"}), short, assert.False},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(test.name, func() {
|
||||
t := suite.T()
|
||||
|
||||
scopes := setScopesToDefault(test.scope)
|
||||
var aMatch bool
|
||||
for _, scope := range scopes {
|
||||
pvs, err := TeamsChatsChat.pathValues(repoRef, ent, Config{})
|
||||
require.NoError(t, err)
|
||||
|
||||
if matchesPathValues(scope, TeamsChatsChat, pvs) {
|
||||
aMatch = true
|
||||
break
|
||||
}
|
||||
}
|
||||
test.expect(t, aMatch)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsRestore_Reduce() {
|
||||
chat, err := path.Build("tid", "uid", path.TeamsChatsService, path.ChatsCategory, true, "cid")
|
||||
require.NoError(suite.T(), err, clues.ToCore(err))
|
||||
|
||||
toRR := func(p path.Path) string {
|
||||
newElems := []string{}
|
||||
|
||||
for _, e := range p.Folders() {
|
||||
newElems = append(newElems, e+".d")
|
||||
}
|
||||
|
||||
joinedFldrs := strings.Join(newElems, "/")
|
||||
|
||||
return stubRepoRef(p.Service(), p.Category(), p.ProtectedResource(), joinedFldrs, p.Item())
|
||||
}
|
||||
|
||||
makeDeets := func(refs ...path.Path) *details.Details {
|
||||
deets := &details.Details{
|
||||
DetailsModel: details.DetailsModel{
|
||||
Entries: []details.Entry{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, r := range refs {
|
||||
itype := details.UnknownType
|
||||
|
||||
switch r {
|
||||
case chat:
|
||||
itype = details.TeamsChat
|
||||
}
|
||||
|
||||
deets.Entries = append(deets.Entries, details.Entry{
|
||||
RepoRef: toRR(r),
|
||||
// Don't escape because we assume nice paths.
|
||||
LocationRef: r.Folder(false),
|
||||
ItemInfo: details.ItemInfo{
|
||||
TeamsChats: &details.TeamsChatsInfo{
|
||||
ItemType: itype,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return deets
|
||||
}
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
deets *details.Details
|
||||
makeSelector func() *TeamsChatsRestore
|
||||
expect []string
|
||||
}{
|
||||
{
|
||||
"no refs",
|
||||
makeDeets(),
|
||||
func() *TeamsChatsRestore {
|
||||
er := NewTeamsChatsRestore(Any())
|
||||
er.Include(er.AllData())
|
||||
return er
|
||||
},
|
||||
[]string{},
|
||||
},
|
||||
{
|
||||
"chat only",
|
||||
makeDeets(chat),
|
||||
func() *TeamsChatsRestore {
|
||||
er := NewTeamsChatsRestore(Any())
|
||||
er.Include(er.AllData())
|
||||
return er
|
||||
},
|
||||
[]string{toRR(chat)},
|
||||
},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(test.name, func() {
|
||||
t := suite.T()
|
||||
|
||||
ctx, flush := tester.NewContext(t)
|
||||
defer flush()
|
||||
|
||||
sel := test.makeSelector()
|
||||
results := sel.Reduce(ctx, test.deets, fault.New(true))
|
||||
paths := results.Paths()
|
||||
assert.Equal(t, test.expect, paths)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsRestore_Reduce_locationRef() {
|
||||
var (
|
||||
chat = stubRepoRef(path.TeamsChatsService, path.ChatsCategory, "uid", "", "cid")
|
||||
chatLocation = "chatname"
|
||||
)
|
||||
|
||||
makeDeets := func(refs ...string) *details.Details {
|
||||
deets := &details.Details{
|
||||
DetailsModel: details.DetailsModel{
|
||||
Entries: []details.Entry{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, r := range refs {
|
||||
var (
|
||||
location string
|
||||
itype = details.UnknownType
|
||||
)
|
||||
|
||||
switch r {
|
||||
case chat:
|
||||
itype = details.TeamsChat
|
||||
location = chatLocation
|
||||
}
|
||||
|
||||
deets.Entries = append(deets.Entries, details.Entry{
|
||||
RepoRef: r,
|
||||
LocationRef: location,
|
||||
ItemInfo: details.ItemInfo{
|
||||
TeamsChats: &details.TeamsChatsInfo{
|
||||
ItemType: itype,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return deets
|
||||
}
|
||||
|
||||
arr := func(s ...string) []string {
|
||||
return s
|
||||
}
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
deets *details.Details
|
||||
makeSelector func() *TeamsChatsRestore
|
||||
expect []string
|
||||
}{
|
||||
{
|
||||
"no refs",
|
||||
makeDeets(),
|
||||
func() *TeamsChatsRestore {
|
||||
er := NewTeamsChatsRestore(Any())
|
||||
er.Include(er.AllData())
|
||||
return er
|
||||
},
|
||||
[]string{},
|
||||
},
|
||||
{
|
||||
"chat only",
|
||||
makeDeets(chat),
|
||||
func() *TeamsChatsRestore {
|
||||
er := NewTeamsChatsRestore(Any())
|
||||
er.Include(er.AllData())
|
||||
return er
|
||||
},
|
||||
arr(chat),
|
||||
},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(test.name, func() {
|
||||
t := suite.T()
|
||||
|
||||
ctx, flush := tester.NewContext(t)
|
||||
defer flush()
|
||||
|
||||
sel := test.makeSelector()
|
||||
results := sel.Reduce(ctx, test.deets, fault.New(true))
|
||||
paths := results.Paths()
|
||||
assert.Equal(t, test.expect, paths)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestScopesByCategory() {
|
||||
var (
|
||||
cs = NewTeamsChatsRestore(Any())
|
||||
teamsChats = cs.Chats(Any())
|
||||
)
|
||||
|
||||
type expect struct {
|
||||
chat int
|
||||
}
|
||||
|
||||
type input []scope
|
||||
|
||||
makeInput := func(cs ...[]TeamsChatsScope) []scope {
|
||||
mss := []scope{}
|
||||
|
||||
for _, sl := range cs {
|
||||
for _, s := range sl {
|
||||
mss = append(mss, scope(s))
|
||||
}
|
||||
}
|
||||
|
||||
return mss
|
||||
}
|
||||
cats := map[path.CategoryType]teamsChatsCategory{
|
||||
path.ChatsCategory: TeamsChatsChat,
|
||||
}
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
scopes input
|
||||
expect expect
|
||||
}{
|
||||
{"teamsChats only", makeInput(teamsChats), expect{1}},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(test.name, func() {
|
||||
t := suite.T()
|
||||
|
||||
result := scopesByCategory[TeamsChatsScope](test.scopes, cats, false)
|
||||
assert.Len(t, result[TeamsChatsChat], test.expect.chat)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestPasses() {
|
||||
const (
|
||||
chatID = "chatID"
|
||||
cat = TeamsChatsChat
|
||||
)
|
||||
|
||||
short := "thisisahashofsomekind"
|
||||
entry := details.Entry{
|
||||
ShortRef: short,
|
||||
ItemRef: chatID,
|
||||
}
|
||||
|
||||
repoRef, err := path.Build("tid", "user", path.TeamsChatsService, path.ChatsCategory, true, chatID)
|
||||
require.NoError(suite.T(), err, clues.ToCore(err))
|
||||
|
||||
var (
|
||||
cs = NewTeamsChatsRestore(Any())
|
||||
otherChat = setScopesToDefault(cs.Chats([]string{"smarf"}))
|
||||
chat = setScopesToDefault(cs.Chats([]string{chatID}))
|
||||
noChat = setScopesToDefault(cs.Chats(None()))
|
||||
allChats = setScopesToDefault(cs.Chats(Any()))
|
||||
ent = details.Entry{
|
||||
RepoRef: repoRef.String(),
|
||||
}
|
||||
)
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
excludes, filters, includes []TeamsChatsScope
|
||||
expect assert.BoolAssertionFunc
|
||||
}{
|
||||
{"empty", nil, nil, nil, assert.False},
|
||||
{"in Chat", nil, nil, chat, assert.True},
|
||||
{"in Other", nil, nil, otherChat, assert.False},
|
||||
{"in no Chat", nil, nil, noChat, assert.False},
|
||||
{"ex None filter chat", allChats, chat, nil, assert.False},
|
||||
{"ex Chat", chat, nil, allChats, assert.False},
|
||||
{"ex Other", otherChat, nil, allChats, assert.True},
|
||||
{"in and ex Chat", chat, nil, chat, assert.False},
|
||||
{"filter Chat", nil, chat, allChats, assert.True},
|
||||
{"filter Other", nil, otherChat, allChats, assert.False},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(test.name, func() {
|
||||
t := suite.T()
|
||||
|
||||
pvs, err := cat.pathValues(repoRef, ent, Config{})
|
||||
require.NoError(t, err)
|
||||
|
||||
result := passes(
|
||||
cat,
|
||||
pvs,
|
||||
entry,
|
||||
test.excludes,
|
||||
test.filters,
|
||||
test.includes)
|
||||
test.expect(t, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestContains() {
|
||||
target := "fnords"
|
||||
|
||||
var (
|
||||
cs = NewTeamsChatsRestore(Any())
|
||||
noChat = setScopesToDefault(cs.Chats(None()))
|
||||
does = setScopesToDefault(cs.Chats([]string{target}))
|
||||
doesNot = setScopesToDefault(cs.Chats([]string{"smarf"}))
|
||||
)
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
scopes []TeamsChatsScope
|
||||
expect assert.BoolAssertionFunc
|
||||
}{
|
||||
{"no chat", noChat, assert.False},
|
||||
{"does contain", does, assert.True},
|
||||
{"does not contain", doesNot, assert.False},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(test.name, func() {
|
||||
t := suite.T()
|
||||
|
||||
var result bool
|
||||
for _, scope := range test.scopes {
|
||||
if scope.Matches(TeamsChatsChat, target) {
|
||||
result = true
|
||||
break
|
||||
}
|
||||
}
|
||||
test.expect(t, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestIsAny() {
|
||||
var (
|
||||
cs = NewTeamsChatsRestore(Any())
|
||||
specificChat = setScopesToDefault(cs.Chats([]string{"chat"}))
|
||||
anyChat = setScopesToDefault(cs.Chats(Any()))
|
||||
)
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
scopes []TeamsChatsScope
|
||||
cat teamsChatsCategory
|
||||
expect assert.BoolAssertionFunc
|
||||
}{
|
||||
{"specific chat", specificChat, TeamsChatsChat, assert.False},
|
||||
{"any chat", anyChat, TeamsChatsChat, assert.True},
|
||||
{"wrong category", anyChat, TeamsChatsUser, assert.False},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(test.name, func() {
|
||||
t := suite.T()
|
||||
|
||||
var result bool
|
||||
for _, scope := range test.scopes {
|
||||
if scope.IsAny(test.cat) {
|
||||
result = true
|
||||
break
|
||||
}
|
||||
}
|
||||
test.expect(t, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsCategory_leafCat() {
|
||||
table := []struct {
|
||||
cat teamsChatsCategory
|
||||
expect teamsChatsCategory
|
||||
}{
|
||||
{teamsChatsCategory("foo"), teamsChatsCategory("foo")},
|
||||
{TeamsChatsCategoryUnknown, TeamsChatsCategoryUnknown},
|
||||
{TeamsChatsUser, TeamsChatsUser},
|
||||
{TeamsChatsChat, TeamsChatsChat},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(test.cat.String(), func() {
|
||||
assert.Equal(suite.T(), test.expect, test.cat.leafCat(), test.cat.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsCategory_PathValues() {
|
||||
t := suite.T()
|
||||
|
||||
chatPath, err := path.Build("tid", "u", path.TeamsChatsService, path.ChatsCategory, true, "chatitem.d")
|
||||
require.NoError(t, err, clues.ToCore(err))
|
||||
|
||||
chatLoc, err := path.Build("tid", "u", path.TeamsChatsService, path.ChatsCategory, true, "chatitem")
|
||||
require.NoError(t, err, clues.ToCore(err))
|
||||
|
||||
var (
|
||||
chatMap = map[categorizer][]string{
|
||||
TeamsChatsChat: {chatPath.Item(), "chat-short"},
|
||||
}
|
||||
chatOnlyNameMap = map[categorizer][]string{
|
||||
TeamsChatsChat: {"chat-short"},
|
||||
}
|
||||
)
|
||||
|
||||
table := []struct {
|
||||
cat teamsChatsCategory
|
||||
path path.Path
|
||||
loc path.Path
|
||||
short string
|
||||
expect map[categorizer][]string
|
||||
expectOnlyName map[categorizer][]string
|
||||
}{
|
||||
{TeamsChatsChat, chatPath, chatLoc, "chat-short", chatMap, chatOnlyNameMap},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(string(test.cat), func() {
|
||||
t := suite.T()
|
||||
ent := details.Entry{
|
||||
RepoRef: test.path.String(),
|
||||
ShortRef: test.short,
|
||||
LocationRef: test.loc.Folder(true),
|
||||
ItemRef: test.path.Item(),
|
||||
}
|
||||
|
||||
pvs, err := test.cat.pathValues(test.path, ent, Config{})
|
||||
require.NoError(t, err)
|
||||
|
||||
for k := range test.expect {
|
||||
assert.ElementsMatch(t, test.expect[k], pvs[k])
|
||||
}
|
||||
|
||||
pvs, err = test.cat.pathValues(test.path, ent, Config{OnlyMatchItemNames: true})
|
||||
require.NoError(t, err)
|
||||
|
||||
for k := range test.expectOnlyName {
|
||||
assert.ElementsMatch(t, test.expectOnlyName[k], pvs[k], k)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestTeamsChatsCategory_PathKeys() {
|
||||
chat := []categorizer{TeamsChatsChat}
|
||||
user := []categorizer{TeamsChatsUser}
|
||||
|
||||
var empty []categorizer
|
||||
|
||||
table := []struct {
|
||||
cat teamsChatsCategory
|
||||
expect []categorizer
|
||||
}{
|
||||
{TeamsChatsCategoryUnknown, empty},
|
||||
{TeamsChatsChat, chat},
|
||||
{TeamsChatsUser, user},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(string(test.cat), func() {
|
||||
assert.Equal(suite.T(), test.cat.pathKeys(), test.expect)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestCategoryFromItemType() {
|
||||
table := []struct {
|
||||
name string
|
||||
input details.ItemType
|
||||
expect teamsChatsCategory
|
||||
}{
|
||||
{
|
||||
name: "chat",
|
||||
input: details.TeamsChat,
|
||||
expect: TeamsChatsChat,
|
||||
},
|
||||
{
|
||||
name: "unknown",
|
||||
input: details.UnknownType,
|
||||
expect: TeamsChatsCategoryUnknown,
|
||||
},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(test.name, func() {
|
||||
t := suite.T()
|
||||
|
||||
result := teamsChatsCategoryFromItemType(test.input)
|
||||
assert.Equal(t, test.expect, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TeamsChatsSelectorSuite) TestCategory_PathType() {
|
||||
table := []struct {
|
||||
cat teamsChatsCategory
|
||||
pathType path.CategoryType
|
||||
}{
|
||||
{TeamsChatsCategoryUnknown, path.UnknownCategory},
|
||||
{TeamsChatsChat, path.ChatsCategory},
|
||||
{TeamsChatsUser, path.UnknownCategory},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(test.cat.String(), func() {
|
||||
assert.Equal(suite.T(), test.pathType, test.cat.PathType())
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user