package selectors import ( "testing" "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/filters" "github.com/alcionai/corso/src/pkg/path" ) // --------------------------------------------------------------------------- // tests // --------------------------------------------------------------------------- type SelectorScopesSuite struct { suite.Suite } func TestSelectorScopesSuite(t *testing.T) { suite.Run(t, new(SelectorScopesSuite)) } func (suite *SelectorScopesSuite) TestContains() { table := []struct { name string scope func() mockScope check string expect assert.BoolAssertionFunc }{ { name: "any", scope: func() mockScope { stub := stubScope("") return stub }, check: rootCatStub.String(), expect: assert.True, }, { name: "none", scope: func() mockScope { stub := stubScope("") stub[rootCatStub.String()] = failAny return stub }, check: rootCatStub.String(), expect: assert.False, }, { name: "blank value", scope: func() mockScope { stub := stubScope("") stub[rootCatStub.String()] = filters.Equal("") return stub }, check: rootCatStub.String(), expect: assert.False, }, { name: "blank target", scope: func() mockScope { stub := stubScope("") stub[rootCatStub.String()] = filterize(scopeConfig{}, "fnords") return stub }, check: "", expect: assert.False, }, { name: "matching target", scope: func() mockScope { stub := stubScope("") stub[rootCatStub.String()] = filterize(scopeConfig{}, rootCatStub.String()) return stub }, check: rootCatStub.String(), expect: assert.True, }, { name: "non-matching target", scope: func() mockScope { stub := stubScope("") stub[rootCatStub.String()] = filterize(scopeConfig{}, rootCatStub.String()) return stub }, check: "smarf", expect: assert.False, }, } for _, test := range table { suite.T().Run(test.name, func(t *testing.T) { test.expect( t, matches(test.scope(), rootCatStub, test.check)) }) } } func (suite *SelectorScopesSuite) TestGetCatValue() { t := suite.T() stub := stubScope("") stub[rootCatStub.String()] = filterize(scopeConfig{}, rootCatStub.String()) assert.Equal(t, []string{rootCatStub.String()}, getCatValue(stub, rootCatStub)) assert.Equal(t, None(), getCatValue(stub, mockCategorizer("foo"))) } func (suite *SelectorScopesSuite) TestIsAnyTarget() { t := suite.T() stub := stubScope("") assert.True(t, isAnyTarget(stub, rootCatStub)) assert.True(t, isAnyTarget(stub, leafCatStub)) assert.False(t, isAnyTarget(stub, mockCategorizer("smarf"))) stub = stubScope("none") assert.False(t, isAnyTarget(stub, rootCatStub)) assert.False(t, isAnyTarget(stub, leafCatStub)) assert.False(t, isAnyTarget(stub, mockCategorizer("smarf"))) } var reduceTestTable = []struct { name string sel func() mockSel expectLen int expectPassesReduce assert.BoolAssertionFunc expectPasses assert.BoolAssertionFunc }{ { name: "include all resource owners", sel: func() mockSel { sel := stubSelector(Any()) sel.Filters = nil sel.Excludes = nil return sel }, expectLen: 1, expectPasses: assert.True, }, { name: "include all scopes", sel: func() mockSel { sel := stubSelector(Any()) sel.Filters = nil sel.Excludes = nil return sel }, expectLen: 1, expectPasses: assert.True, }, { name: "include none resource owners", sel: func() mockSel { sel := stubSelector(None()) sel.Includes[0] = scope(stubScope(AnyTgt)) sel.Filters = nil sel.Excludes = nil return sel }, expectLen: 0, expectPasses: assert.True, // passes() does not check owners }, { name: "include none scopes", sel: func() mockSel { sel := stubSelector(Any()) sel.Includes[0] = scope(stubScope("none")) sel.Filters = nil sel.Excludes = nil return sel }, expectLen: 0, expectPasses: assert.False, }, { name: "filter and include all", sel: func() mockSel { sel := stubSelector(Any()) sel.Excludes = nil return sel }, expectLen: 1, expectPasses: assert.True, }, { name: "include all filter none", sel: func() mockSel { sel := stubSelector(Any()) sel.Filters[0] = scope(stubInfoScope("none")) sel.Excludes = nil return sel }, expectLen: 0, expectPasses: assert.False, }, { name: "include all exclude all", sel: func() mockSel { sel := stubSelector(Any()) sel.Filters = nil return sel }, expectLen: 0, expectPasses: assert.False, }, { name: "include all exclude none", sel: func() mockSel { sel := stubSelector(Any()) sel.Filters = nil sel.Excludes[0] = scope(stubScope("none")) return sel }, expectLen: 1, expectPasses: assert.True, }, { name: "filter all exclude all", sel: func() mockSel { sel := stubSelector(Any()) sel.Includes = nil return sel }, expectLen: 0, expectPasses: assert.False, }, { name: "filter all exclude none", sel: func() mockSel { sel := stubSelector(Any()) sel.Includes = nil sel.Excludes[0] = scope(stubScope("none")) return sel }, expectLen: 1, expectPasses: assert.True, }, } func (suite *SelectorScopesSuite) TestReduce() { deets := func() details.Details { return details.Details{ DetailsModel: details.DetailsModel{ Entries: []details.DetailsEntry{ { RepoRef: stubRepoRef( pathServiceStub, pathCatStub, rootCatStub.String(), "stub", leafCatStub.String(), ), }, }, }, } } dataCats := map[path.CategoryType]mockCategorizer{ pathCatStub: rootCatStub, } for _, test := range reduceTestTable { suite.T().Run(test.name, func(t *testing.T) { ctx, flush := tester.NewContext() defer flush() ds := deets() result := reduce[mockScope]( ctx, &ds, test.sel().Selector, dataCats) require.NotNil(t, result) assert.Len(t, result.Entries, test.expectLen) }) } } func (suite *SelectorScopesSuite) TestScopesByCategory() { t := suite.T() s1 := stubScope("") s2 := stubScope("") s2[scopeKeyCategory] = filterize(scopeConfig{}, unknownCatStub.String()) result := scopesByCategory[mockScope]( []scope{scope(s1), scope(s2)}, map[path.CategoryType]mockCategorizer{ path.UnknownCategory: rootCatStub, }, false) assert.Len(t, result, 1) assert.Len(t, result[rootCatStub], 2) assert.Empty(t, result[leafCatStub]) } func (suite *SelectorScopesSuite) TestPasses() { cat := rootCatStub pth := stubPath(suite.T(), "uid", []string{"fld"}, path.EventsCategory) pathVals := cat.pathValues(pth) entry := details.DetailsEntry{} for _, test := range reduceTestTable { suite.T().Run(test.name, func(t *testing.T) { sel := test.sel() excl := toMockScope(sel.Excludes) filt := toMockScope(sel.Filters) incl := toMockScope(sel.Includes) result := passes( cat, pathVals, entry, excl, filt, incl) test.expectPasses(t, result) }) } } func toMockScope(sc []scope) []mockScope { if len(sc) == 0 { return nil } ms := []mockScope{} for _, s := range sc { ms = append(ms, mockScope(s)) } return ms } func (suite *SelectorScopesSuite) TestMatchesPathValues() { cat := rootCatStub pvs := stubPathValues() short := "brunheelda" table := []struct { name string cat mockCategorizer rootVal string leafVal string shortRef string expect assert.BoolAssertionFunc }{ { name: "matching values", rootVal: rootCatStub.String(), leafVal: leafCatStub.String(), expect: assert.True, }, { name: "any", rootVal: AnyTgt, leafVal: AnyTgt, expect: assert.True, }, { name: "none", rootVal: NoneTgt, leafVal: NoneTgt, expect: assert.False, }, { name: "mismatched values", rootVal: "fnords", leafVal: "smarf", expect: assert.False, }, { name: "leaf matches shortRef", rootVal: rootCatStub.String(), leafVal: short, shortRef: short, expect: assert.True, }, } for _, test := range table { suite.T().Run(test.name, func(t *testing.T) { sc := stubScope("") sc[rootCatStub.String()] = filterize(scopeConfig{}, test.rootVal) sc[leafCatStub.String()] = filterize(scopeConfig{}, test.leafVal) test.expect(t, matchesPathValues(sc, cat, pvs, test.shortRef)) }) } } func (suite *SelectorScopesSuite) TestAddToSet() { t := suite.T() set := []string{} set = addToSet(set, []string{}) assert.Len(t, set, 0) set = addToSet(set, []string{"a"}) assert.Len(t, set, 1) assert.Equal(t, set[0], "a") set = addToSet(set, []string{"a"}) assert.Len(t, set, 1) set = addToSet(set, []string{"a", "b"}) assert.Len(t, set, 2) assert.Equal(t, set[0], "a") assert.Equal(t, set[1], "b") set = addToSet(set, []string{"c", "d"}) assert.Len(t, set, 4) assert.Equal(t, set[0], "a") assert.Equal(t, set[1], "b") assert.Equal(t, set[2], "c") assert.Equal(t, set[3], "d") } func (suite *SelectorScopesSuite) TestClean() { table := []struct { name string input []string expect []string }{ { name: "nil", input: nil, expect: None(), }, { name: "has anyTgt", input: []string{"a", AnyTgt}, expect: Any(), }, { name: "has noneTgt", input: []string{"a", NoneTgt}, expect: None(), }, { name: "has anyTgt and noneTgt, any first", input: []string{"a", AnyTgt, NoneTgt}, expect: Any(), }, { name: "has noneTgt and anyTgt, none first", input: []string{"a", NoneTgt, AnyTgt}, expect: None(), }, { name: "already clean", input: []string{"a", "b"}, expect: []string{"a", "b"}, }, } for _, test := range table { suite.T().Run(test.name, func(t *testing.T) { result := clean(test.input) assert.Equal(t, result, test.expect) }) } } func (suite *SelectorScopesSuite) TestWrapFilter() { table := []struct { name string filter filterFunc input []string comparator int target string }{ { name: "any", filter: filters.Contains, input: Any(), comparator: int(filters.Passes), target: AnyTgt, }, { name: "none", filter: filters.In, input: None(), comparator: int(filters.Fails), target: NoneTgt, }, { name: "something", filter: filters.Equal, input: []string{"userid"}, comparator: int(filters.EqualTo), target: "userid", }, } for _, test := range table { suite.T().Run(test.name, func(t *testing.T) { ff := wrapFilter(test.filter)(test.input) assert.Equal(t, int(ff.Comparator), test.comparator) assert.Equal(t, ff.Target, test.target) }) } } func (suite *SelectorScopesSuite) TestScopeConfig() { input := "input" table := []struct { name string config scopeConfig expect int }{ { name: "no configs set", config: scopeConfig{}, expect: int(filters.EqualTo), }, { name: "force prefix", config: scopeConfig{usePrefixFilter: true}, expect: int(filters.TargetPrefixes), }, } for _, test := range table { suite.T().Run(test.name, func(t *testing.T) { result := filterize(test.config, input) assert.Equal(t, test.expect, int(result.Comparator)) }) } } func (suite *SelectorScopesSuite) TestDiscreteCopy() { var ( t = suite.T() orig = stubScope(AnyTgt) clone = discreteCopy(orig, "fnords") ) for k, v := range orig { if k != rootCatStub.String() { assert.Equal(t, v.Target, clone[k].Target) } else { assert.Equal(t, AnyTgt, v.Target) assert.Equal(t, "fnords", clone[k].Target) } } }