diff --git a/src/pkg/filters/comparator_string.go b/src/pkg/filters/comparator_string.go deleted file mode 100644 index e6afe098c..000000000 --- a/src/pkg/filters/comparator_string.go +++ /dev/null @@ -1,37 +0,0 @@ -// Code generated by "stringer -type=comparator -linecomment"; DO NOT EDIT. - -package filters - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[UnknownComparator-0] - _ = x[EqualTo-1] - _ = x[GreaterThan-2] - _ = x[LessThan-3] - _ = x[TargetContains-4] - _ = x[TargetIn-5] - _ = x[Passes-6] - _ = x[Fails-7] - _ = x[IdentityValue-8] - _ = x[TargetPrefixes-9] - _ = x[TargetSuffixes-10] - _ = x[TargetPathPrefix-11] - _ = x[TargetPathContains-12] - _ = x[TargetPathSuffix-13] - _ = x[TargetPathEquals-14] -} - -const _comparator_name = "UnknownComparisonEQGTLTContINPassFailIdentityPfxSfxPathPfxPathContPathSfxPathEQ" - -var _comparator_index = [...]uint8{0, 17, 19, 21, 23, 27, 29, 33, 37, 45, 48, 51, 58, 66, 73, 79} - -func (i comparator) String() string { - if i < 0 || i >= comparator(len(_comparator_index)-1) { - return "comparator(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _comparator_name[_comparator_index[i]:_comparator_index[i+1]] -} diff --git a/src/pkg/filters/filters.go b/src/pkg/filters/filters.go index 67f2aaa34..638d578db 100644 --- a/src/pkg/filters/filters.go +++ b/src/pkg/filters/filters.go @@ -11,41 +11,47 @@ import ( "github.com/alcionai/corso/src/pkg/path" ) -type comparator int +type comparator string //go:generate stringer -type=comparator -linecomment const ( - UnknownComparator comparator = iota // UnknownComparison - // a == b - EqualTo // EQ + UnknownComparator comparator = "" + // norm(a) == norm(b) + EqualTo = "EQ" + // a === b + StrictEqualTo = "StrictEQ" // a > b - GreaterThan // GT + GreaterThan = "GT" // a < b - LessThan // LT + LessThan = "LT" // "foo,bar,baz" contains "foo" - TargetContains // Cont + TargetContains = "Cont" // "foo" is found in "foo,bar,baz" - TargetIn // IN + TargetIn = "IN" // always passes - Passes // Pass + Passes = "Pass" // always fails - Fails // Fail + Fails = "Fail" // passthrough for the target - IdentityValue // Identity + IdentityValue = "Identity" // "foo" is a prefix of "foobarbaz" - TargetPrefixes // Pfx + TargetPrefixes = "Pfx" // "baz" is a suffix of "foobarbaz" - TargetSuffixes // Sfx + TargetSuffixes = "Sfx" // "foo" equals any complete element prefix of "foo/bar/baz" - TargetPathPrefix // PathPfx + TargetPathPrefix = "PathPfx" // "foo" equals any complete element in "foo/bar/baz" - TargetPathContains // PathCont + TargetPathContains = "PathCont" // "baz" equals any complete element suffix of "foo/bar/baz" - TargetPathSuffix // PathSfx + TargetPathSuffix = "PathSfx" // "foo/bar/baz" equals the complete path "foo/bar/baz" - TargetPathEquals // PathEQ + TargetPathEquals = "PathEQ" ) +func (c comparator) String() string { + return string(c) +} + func normAll(ss []string) []string { r := slices.Clone(ss) for i := range r { @@ -56,7 +62,7 @@ func normAll(ss []string) []string { } func norm(s string) string { - return strings.ToLower(s) + return strings.ToLower(strings.TrimSpace(s)) } // normPathElem ensures the string is: @@ -66,6 +72,8 @@ func norm(s string) string { // without re-running the prefix-suffix addition multiple // times per target. func normPathElem(s string) string { + s = strings.TrimSpace(s) + if len(s) == 0 { return s } @@ -74,7 +82,9 @@ func normPathElem(s string) string { s = string(path.PathSeparator) + s } - s = path.TrimTrailingSlash(s) + string(path.PathSeparator) + s = path.TrimTrailingSlash(s) + s = strings.ToLower(s) + s += string(path.PathSeparator) return s } @@ -83,7 +93,7 @@ func normPathElem(s string) string { // compare values against. Filter.Matches(v) returns // true if Filter.Comparer(filter.target, v) is true. type Filter struct { - Comparator comparator `json:"comparator"` + Comparator comparator `json:"comparator_type"` // the type of comparison Targets []string `json:"targets"` // the set of values to compare NormalizedTargets []string `json:"normalizedTargets"` // the set of comparable values post normalization Negate bool `json:"negate"` // when true, negate the comparator result @@ -92,7 +102,8 @@ type Filter struct { Identity string `json:"identity"` // deprecated, kept around for deserialization - Target string `json:"target"` // the value to compare against + Target string `json:"target"` // the value to compare against + ComparatorInt int `json:"comparator"` } // ---------------------------------------------------------------------------------------------------- @@ -111,7 +122,7 @@ func Identity(id string) Filter { } // Equal creates a filter where Compare(v) is true if, for any target string, -// target == v +// norm(target) == norm(v) func Equal(target []string) Filter { return newFilter(EqualTo, target, normAll(target), false) } @@ -122,6 +133,19 @@ func NotEqual(target []string) Filter { return newFilter(EqualTo, target, normAll(target), true) } +// StrictEqual creates a filter where Compare(v) is true if, for any target string, +// target === v. Target and v are not normalized for this comparison. The comparison +// is case sensitive and ignores character folding. +func StrictEqual(target []string) Filter { + return newFilter(StrictEqualTo, target, normAll(target), false) +} + +// NotStrictEqual creates a filter where Compare(v) is true if, for any target string, +// target != v +func NotStrictEqual(target []string) Filter { + return newFilter(StrictEqualTo, target, normAll(target), true) +} + // Greater creates a filter where Compare(v) is true if, for any target string, // target > v func Greater(target []string) Filter { @@ -356,29 +380,24 @@ func (f Filter) CompareAny(inputs ...string) bool { func (f Filter) Compare(input string) bool { var cmp func(string, string) bool + // select comparison func switch f.Comparator { - case EqualTo, IdentityValue: + case EqualTo, IdentityValue, TargetPathEquals: cmp = equals + case StrictEqualTo: + cmp = strictEquals case GreaterThan: cmp = greater case LessThan: cmp = less - case TargetContains: + case TargetContains, TargetPathContains: cmp = contains case TargetIn: cmp = in - case TargetPrefixes: + case TargetPrefixes, TargetPathPrefix: cmp = prefixed - case TargetSuffixes: + case TargetSuffixes, TargetPathSuffix: cmp = suffixed - case TargetPathPrefix: - cmp = pathPrefix - case TargetPathContains: - cmp = pathContains - case TargetPathSuffix: - cmp = pathSuffix - case TargetPathEquals: - cmp = pathEquals case Passes: return true case Fails: @@ -388,14 +407,39 @@ func (f Filter) Compare(input string) bool { var ( res bool targets = f.NormalizedTargets + _input = norm(input) + // most comparators expect cmp(target, input) + // path comparators expect cmp(input, target) + swapParams bool ) + // set conditional behavior + switch f.Comparator { + case TargetContains: + // legacy case handling for contains, which checks for + // strings.Contains(target, input) instead of (input, target) + swapParams = true + case StrictEqualTo: + targets = f.Targets + _input = input + case TargetPathPrefix, TargetPathContains, TargetPathSuffix, TargetPathEquals: + // As a precondition, assumes each entry in the NormalizedTargets + // list has been passed through normPathElem(). + _input = normPathElem(input) + } + if len(targets) == 0 { targets = f.Targets } for _, tgt := range targets { - res = cmp(norm(tgt), norm(input)) + t, i := tgt, _input + + if swapParams { + t, i = _input, tgt + } + + res = cmp(t, i) // any-match if res { @@ -410,11 +454,16 @@ func (f Filter) Compare(input string) bool { return res } -// true if t == i +// true if t == i, case insensitive and folded func equals(target, input string) bool { return strings.EqualFold(target, input) } +// true if t == i, case sensitive and not folded +func strictEquals(target, input string) bool { + return target == input +} + // true if t > i func greater(target, input string) bool { return target > input @@ -425,9 +474,9 @@ func less(target, input string) bool { return target < input } -// true if target contains input as a substring. +// true if input contains target as a substring. func contains(target, input string) bool { - return strings.Contains(target, input) + return strings.Contains(input, target) } // true if input contains target as a substring. @@ -445,63 +494,6 @@ func suffixed(target, input string) bool { return strings.HasSuffix(input, target) } -// true if target is an _element complete_ prefix match -// on the input. Element complete means we do not -// succeed on partial element matches (ex: "/foo" does -// not match "/foobar"). -// -// As a precondition, assumes the target value has been -// passed through normPathElem(). -// -// The input is assumed to be the complete path that may -// have the target as a prefix. -func pathPrefix(target, input string) bool { - return strings.HasPrefix(normPathElem(input), target) -} - -// true if target has an _element complete_ equality -// with any element, or any sequence of elements, from -// the input. Element complete means we do not succeed -// on partial element matches (ex: foo does not match -// /foobar, and foo/bar does not match foo/barbaz). -// -// As a precondition, assumes the target value has been -// passed through normPathElem(). -// -// Input is assumed to be the complete path that may -// contain the target as an element or sequence of elems. -func pathContains(target, input string) bool { - return strings.Contains(normPathElem(input), target) -} - -// true if target is an _element complete_ suffix match -// on the input. Element complete means we do not -// succeed on partial element matches (ex: "/bar" does -// not match "/foobar"). -// -// As a precondition, assumes the target value has been -// passed through normPathElem(). -// -// The input is assumed to be the complete path that may -// have the target as a suffix. -func pathSuffix(target, input string) bool { - return strings.HasSuffix(normPathElem(input), target) -} - -// true if target is an _exact_ match on the input, excluding -// path delmiters. Element complete means we do not succeed -// on partial element matches (ex: "/bar" does not match -// "/foobar"). -// -// As a precondition, assumes the target value has been -// passed through normPathElem(). -// -// The input is assumed to be the complete path that may -// match the target. -func pathEquals(target, input string) bool { - return strings.EqualFold(normPathElem(input), target) -} - // ---------------------------------------------------------------------------------------------------- // Printers and PII control // ---------------------------------------------------------------------------------------------------- @@ -511,9 +503,11 @@ var _ clues.PlainConcealer = &Filter{} var safeFilterValues = map[string]struct{}{"*": {}} func (f Filter) Conceal() string { - fcs := f.Comparator.String() + fcs := string(f.Comparator) switch f.Comparator { + case UnknownComparator: + fcs = "UnknownComparison" case Passes, Fails: return fcs } @@ -532,9 +526,11 @@ func (f Filter) String() string { } func (f Filter) PlainString() string { - fcs := f.Comparator.String() + fcs := string(f.Comparator) switch f.Comparator { + case UnknownComparator: + fcs = "UnknownComparison" case Passes, Fails: return fcs } diff --git a/src/pkg/filters/filters_test.go b/src/pkg/filters/filters_test.go index c71ffffa0..ac8820551 100644 --- a/src/pkg/filters/filters_test.go +++ b/src/pkg/filters/filters_test.go @@ -51,6 +51,8 @@ func (suite *FiltersSuite) TestEquals() { expectNF assert.BoolAssertionFunc }{ {"foo", assert.True, assert.False}, + {"FOO", assert.True, assert.False}, + {" foo ", assert.True, assert.False}, {"bar", assert.False, assert.True}, } for _, test := range table { @@ -86,6 +88,30 @@ func (suite *FiltersSuite) TestEquals_any() { } } +func (suite *FiltersSuite) TestStrictEquals() { + f := filters.StrictEqual(foo) + nf := filters.NotStrictEqual(foo) + + table := []struct { + input string + expectF assert.BoolAssertionFunc + expectNF assert.BoolAssertionFunc + }{ + {"foo", assert.True, assert.False}, + {"FOO", assert.False, assert.True}, + {" foo ", assert.False, assert.True}, + {"bar", assert.False, assert.True}, + } + for _, test := range table { + suite.Run(test.input, func() { + t := suite.T() + + test.expectF(t, f.Compare(test.input), "filter") + test.expectNF(t, nf.Compare(test.input), "negated filter") + }) + } +} + func (suite *FiltersSuite) TestGreater() { f := filters.Greater(five) nf := filters.NotGreater(five) @@ -143,6 +169,7 @@ func (suite *FiltersSuite) TestContains() { }{ {"murf", assert.True, assert.False}, {"frum", assert.False, assert.True}, + {"ssmurfss", assert.False, assert.True}, } for _, test := range table { suite.Run(test.input, func() { @@ -300,77 +327,134 @@ func (suite *FiltersSuite) TestSuffixes() { } } -func (suite *FiltersSuite) TestPathPrefix() { - table := []struct { - name string - targets []string - input string - expectF assert.BoolAssertionFunc - expectNF assert.BoolAssertionFunc - }{ - {"Exact - same case", []string{"fA"}, "/fA", assert.True, assert.False}, - {"Exact - different case", []string{"fa"}, "/fA", assert.True, assert.False}, - {"Prefix - same case", []string{"fA"}, "/fA/fB", assert.True, assert.False}, - {"Prefix - different case", []string{"fa"}, "/fA/fB", assert.True, assert.False}, - {"Exact - multiple folders", []string{"fA/fB"}, "/fA/fB", assert.True, assert.False}, - {"Prefix - single folder partial", []string{"f"}, "/fA/fB", assert.False, assert.True}, - {"Prefix - multi folder partial", []string{"fA/f"}, "/fA/fB", assert.False, assert.True}, - {"Target Longer - single folder", []string{"fA"}, "/f", assert.False, assert.True}, - {"Target Longer - multi folder", []string{"fA/fB"}, "/fA/f", assert.False, assert.True}, - {"Not prefix - single folder", []string{"fA"}, "/af", assert.False, assert.True}, - {"Not prefix - multi folder", []string{"fA/fB"}, "/fA/bf", assert.False, assert.True}, - {"Exact - target variations - none", []string{"fA"}, "/fA", assert.True, assert.False}, - {"Exact - target variations - prefix", []string{"/fA"}, "/fA", assert.True, assert.False}, - {"Exact - target variations - suffix", []string{"fA/"}, "/fA", assert.True, assert.False}, - {"Exact - target variations - both", []string{"/fA/"}, "/fA", assert.True, assert.False}, - {"Exact - input variations - none", []string{"fA"}, "fA", assert.True, assert.False}, - {"Exact - input variations - prefix", []string{"fA"}, "/fA", assert.True, assert.False}, - {"Exact - input variations - suffix", []string{"fA"}, "fA/", assert.True, assert.False}, - {"Exact - input variations - both", []string{"fA"}, "/fA/", assert.True, assert.False}, - {"Prefix - target variations - none", []string{"fA"}, "/fA/fb", assert.True, assert.False}, - {"Prefix - target variations - prefix", []string{"/fA"}, "/fA/fb", assert.True, assert.False}, - {"Prefix - target variations - suffix", []string{"fA/"}, "/fA/fb", assert.True, assert.False}, - {"Prefix - target variations - both", []string{"/fA/"}, "/fA/fb", assert.True, assert.False}, - {"Prefix - input variations - none", []string{"fA"}, "fA/fb", assert.True, assert.False}, - {"Prefix - input variations - prefix", []string{"fA"}, "/fA/fb", assert.True, assert.False}, - {"Prefix - input variations - suffix", []string{"fA"}, "fA/fb/", assert.True, assert.False}, - {"Prefix - input variations - both", []string{"fA"}, "/fA/fb/", assert.True, assert.False}, - {"Slice - one matches", []string{"foo", "fa/f", "fA"}, "/fA/fb", assert.True, assert.False}, - {"Slice - none match", []string{"foo", "fa/f", "f"}, "/fA/fb", assert.False, assert.True}, +// --------------------------------------------------------------------------- +// path comparators +// --------------------------------------------------------------------------- + +var pathElemNormalizationTable = []struct { + name string + targets []string + expect []string +}{ + {"Single - no slash", []string{"fA"}, []string{"/fa/"}}, + {"Single - pre slash", []string{"/fA"}, []string{"/fa/"}}, + {"Single - suff slash", []string{"fA/"}, []string{"/fa/"}}, + {"Single - both slashes", []string{"/fA/"}, []string{"/fa/"}}, + {"Multipath - no slash", []string{"fA/fB"}, []string{"/fa/fb/"}}, + {"Multipath - pre slash", []string{"/fA/fB"}, []string{"/fa/fb/"}}, + {"Multipath - suff slash", []string{"fA/fB/"}, []string{"/fa/fb/"}}, + {"Multipath - both slashes", []string{"/fA/fB/"}, []string{"/fa/fb/"}}, + {"Multi input - no slash", []string{"fA", "fB"}, []string{"/fa/", "/fb/"}}, + {"Multi input - pre slash", []string{"/fA", "/fB"}, []string{"/fa/", "/fb/"}}, + {"Multi input - suff slash", []string{"fA/", "fB/"}, []string{"/fa/", "/fb/"}}, + {"Multi input - both slashes", []string{"/fA/", "/fB/"}, []string{"/fa/", "/fb/"}}, +} + +type baf struct { + fn assert.BoolAssertionFunc + yes bool +} + +var ( + yes = baf{ + fn: assert.True, + yes: true, } - for _, test := range table { + no = baf{ + fn: assert.False, + yes: false, + } +) + +var pathComparisonsTable = []struct { + name string + targets []string + input string + expectContains baf + expectEquals baf + expectPrefix baf + expectSuffix baf +}{ + {"single folder partial", []string{"f"}, "/fA", no, no, no, no}, + {"single folder target partial", []string{"f"}, "/fA/fB", no, no, no, no}, + {"multi folder input partial", []string{"A/f"}, "/fA/fB", no, no, no, no}, + {"longer target - single folder", []string{"fA"}, "/f", no, no, no, no}, + {"longer target - multi folder", []string{"fA/fB"}, "/fA/f", no, no, no, no}, + {"non-matching - single folder", []string{"fA"}, "/af", no, no, no, no}, + {"non-matching - multi folder", []string{"fA/fB"}, "/fA/bf", no, no, no, no}, + + {"Exact - same case", []string{"fA"}, "/fA", yes, yes, yes, yes}, + {"Exact - different case", []string{"fa"}, "/fA", yes, yes, yes, yes}, + {"Exact - multiple folders", []string{"fA/fB"}, "/fA/fB", yes, yes, yes, yes}, + {"Exact - target slash variations - prefix", []string{"/fA"}, "/fA", yes, yes, yes, yes}, + {"Exact - target slash variations - suffix", []string{"fA/"}, "/fA", yes, yes, yes, yes}, + {"Exact - target slash variations - both", []string{"/fA/"}, "/fA", yes, yes, yes, yes}, + {"Exact - input slash variations - none", []string{"fA"}, "fA", yes, yes, yes, yes}, + {"Exact - input slash variations - prefix", []string{"fA"}, "/fA", yes, yes, yes, yes}, + {"Exact - input slash variations - suffix", []string{"fA"}, "fA/", yes, yes, yes, yes}, + {"Exact - input slash variations - both", []string{"fA"}, "/fA/", yes, yes, yes, yes}, + + {"Prefix - same case", []string{"fA"}, "/fA/fB", yes, no, yes, no}, + {"Prefix - different case", []string{"fa"}, "/fA/fB", yes, no, yes, no}, + {"Prefix - multiple folders", []string{"fa/fb"}, "/fA/fB/fC", yes, no, yes, no}, + {"Prefix - target slash variations - none", []string{"fA"}, "/fA/fb", yes, no, yes, no}, + {"Prefix - target slash variations - prefix", []string{"/fA"}, "/fA/fb", yes, no, yes, no}, + {"Prefix - target slash variations - suffix", []string{"fA/"}, "/fA/fb", yes, no, yes, no}, + {"Prefix - target slash variations - both", []string{"/fA/"}, "/fA/fb", yes, no, yes, no}, + {"Prefix - input slash variations - none", []string{"fA"}, "fA/fb", yes, no, yes, no}, + {"Prefix - input slash variations - prefix", []string{"fA"}, "/fA/fb", yes, no, yes, no}, + {"Prefix - input slash variations - suffix", []string{"fA"}, "fA/fb/", yes, no, yes, no}, + {"Prefix - input slash variations - both", []string{"fA"}, "/fA/fb/", yes, no, yes, no}, + + {"Suffix - same case", []string{"fB"}, "/fA/fB", yes, no, no, yes}, + {"Suffix - different case", []string{"fb"}, "/fA/fB", yes, no, no, yes}, + {"Suffix - multiple folders", []string{"fb/fc"}, "/fA/fB/fC", yes, no, no, yes}, + {"Suffix - target slash variations - none", []string{"fB"}, "/fA/fb", yes, no, no, yes}, + {"Suffix - target slash variations - prefix", []string{"/fB"}, "/fA/fb", yes, no, no, yes}, + {"Suffix - target slash variations - suffix", []string{"fB/"}, "/fA/fb", yes, no, no, yes}, + {"Suffix - target slash variations - both", []string{"/fB/"}, "/fA/fb", yes, no, no, yes}, + {"Suffix - input slash variations - none", []string{"fB"}, "fA/fb", yes, no, no, yes}, + {"Suffix - input slash variations - prefix", []string{"fB"}, "/fA/fb", yes, no, no, yes}, + {"Suffix - input slash variations - suffix", []string{"fB"}, "fA/fb/", yes, no, no, yes}, + {"Suffix - input slash variations - both", []string{"fB"}, "/fA/fb/", yes, no, no, yes}, + + {"Contains - same case", []string{"fB"}, "/fA/fB/fC", yes, no, no, no}, + {"Contains - different case", []string{"fb"}, "/fA/fB/fC", yes, no, no, no}, + {"Contains - multiple folders", []string{"fb/fc"}, "/fA/fB/fC/fD", yes, no, no, no}, + {"Contains - target slash variations - none", []string{"fB"}, "/fA/fb/fc", yes, no, no, no}, + {"Contains - target slash variations - prefix", []string{"/fB"}, "/fA/fb/fc", yes, no, no, no}, + {"Contains - target slash variations - suffix", []string{"fB/"}, "/fA/fb/fc", yes, no, no, no}, + {"Contains - target slash variations - both", []string{"/fB/"}, "/fA/fb/fc", yes, no, no, no}, + {"Contains - input slash variations - none", []string{"fB"}, "fA/fb/fc", yes, no, no, no}, + {"Contains - input slash variations - prefix", []string{"fB"}, "/fA/fb/fc/", yes, no, no, no}, + {"Contains - input slash variations - suffix", []string{"fB"}, "fA/fb/fc/", yes, no, no, no}, + {"Contains - input slash variations - both", []string{"fB"}, "/fA/fb/fc/", yes, no, no, no}, + + {"Slice - one exact matches", []string{"foo", "fa/f", "fA"}, "/fA", yes, yes, yes, yes}, + {"Slice - none match", []string{"foo", "fa/f", "f"}, "/fA", no, no, no, no}, +} + +func (suite *FiltersSuite) TestPathPrefix() { + for _, test := range pathComparisonsTable { suite.Run(test.name, func() { - t := suite.T() + var ( + t = suite.T() + f = filters.PathPrefix(test.targets) + nf = filters.NotPathPrefix(test.targets) + ) - f := filters.PathPrefix(test.targets) - nf := filters.NotPathPrefix(test.targets) - - test.expectF(t, f.Compare(test.input), "filter") - test.expectNF(t, nf.Compare(test.input), "negated filter") + test.expectPrefix.fn(t, f.Compare(test.input), "filter") + if test.expectPrefix.yes { + no.fn(t, nf.Compare(test.input), "negated filter") + } else { + yes.fn(t, nf.Compare(test.input), "negated filter") + } }) } } func (suite *FiltersSuite) TestPathPrefix_NormalizedTargets() { - table := []struct { - name string - targets []string - expect []string - }{ - {"Single - no slash", []string{"fA"}, []string{"/fA/"}}, - {"Single - pre slash", []string{"/fA"}, []string{"/fA/"}}, - {"Single - suff slash", []string{"fA/"}, []string{"/fA/"}}, - {"Single - both slashes", []string{"/fA/"}, []string{"/fA/"}}, - {"Multipath - no slash", []string{"fA/fB"}, []string{"/fA/fB/"}}, - {"Multipath - pre slash", []string{"/fA/fB"}, []string{"/fA/fB/"}}, - {"Multipath - suff slash", []string{"fA/fB/"}, []string{"/fA/fB/"}}, - {"Multipath - both slashes", []string{"/fA/fB/"}, []string{"/fA/fB/"}}, - {"Multi input - no slash", []string{"fA", "fB"}, []string{"/fA/", "/fB/"}}, - {"Multi input - pre slash", []string{"/fA", "/fB"}, []string{"/fA/", "/fB/"}}, - {"Multi input - suff slash", []string{"fA/", "fB/"}, []string{"/fA/", "/fB/"}}, - {"Multi input - both slashes", []string{"/fA/", "/fB/"}, []string{"/fA/", "/fB/"}}, - } - for _, test := range table { + for _, test := range pathElemNormalizationTable { suite.Run(test.name, func() { t := suite.T() @@ -381,79 +465,26 @@ func (suite *FiltersSuite) TestPathPrefix_NormalizedTargets() { } func (suite *FiltersSuite) TestPathContains() { - table := []struct { - name string - targets []string - input string - expectF assert.BoolAssertionFunc - expectNF assert.BoolAssertionFunc - }{ - {"Exact - same case", []string{"fA"}, "/fA", assert.True, assert.False}, - {"Exact - different case", []string{"fa"}, "/fA", assert.True, assert.False}, - {"Cont - same case single target", []string{"fA"}, "/Z/fA/B", assert.True, assert.False}, - {"Cont - different case single target", []string{"fA"}, "/z/fa/b", assert.True, assert.False}, - {"Cont - same case multi target", []string{"Z/fA"}, "/Z/fA/B", assert.True, assert.False}, - {"Cont - different case multi target", []string{"fA/B"}, "/z/fa/b", assert.True, assert.False}, - {"Exact - multiple folders", []string{"Z/fA/B"}, "/Z/fA/B", assert.True, assert.False}, - {"Cont - single folder partial", []string{"folder"}, "/Z/fA/fB", assert.False, assert.True}, - {"Cont - multi folder partial", []string{"fA/fold"}, "/Z/fA/fB", assert.False, assert.True}, - {"Target Longer - single folder", []string{"fA"}, "/folder", assert.False, assert.True}, - {"Target Longer - multi folder", []string{"fA/fB"}, "/fA/fold", assert.False, assert.True}, - {"Not cont - single folder", []string{"fA"}, "/afolder", assert.False, assert.True}, - {"Not cont - single target", []string{"fA"}, "/z/afolder/bfolder", assert.False, assert.True}, - {"Not cont - multi folder", []string{"fA/fB"}, "/z/fA/bfolder", assert.False, assert.True}, - {"Exact - target variations - none", []string{"fA"}, "/fA", assert.True, assert.False}, - {"Exact - target variations - prefix", []string{"/fA"}, "/fA", assert.True, assert.False}, - {"Exact - target variations - suffix", []string{"fA/"}, "/fA", assert.True, assert.False}, - {"Exact - target variations - both", []string{"/fA/"}, "/fA", assert.True, assert.False}, - {"Exact - input variations - none", []string{"fA"}, "fA", assert.True, assert.False}, - {"Exact - input variations - prefix", []string{"fA"}, "/fA", assert.True, assert.False}, - {"Exact - input variations - suffix", []string{"fA"}, "fA/", assert.True, assert.False}, - {"Exact - input variations - both", []string{"fA"}, "/fA/", assert.True, assert.False}, - {"Cont - target variations - none", []string{"fA"}, "/fA/fb", assert.True, assert.False}, - {"Cont - target variations - prefix", []string{"/fA"}, "/fA/fb", assert.True, assert.False}, - {"Cont - target variations - suffix", []string{"fA/"}, "/fA/fb", assert.True, assert.False}, - {"Cont - target variations - both", []string{"/fA/"}, "/fA/fb", assert.True, assert.False}, - {"Cont - input variations - none", []string{"fA"}, "fA/fb", assert.True, assert.False}, - {"Cont - input variations - prefix", []string{"fA"}, "/fA/fb", assert.True, assert.False}, - {"Cont - input variations - suffix", []string{"fA"}, "fA/fb/", assert.True, assert.False}, - {"Cont - input variations - both", []string{"fA"}, "/fA/fb/", assert.True, assert.False}, - {"Slice - one matches", []string{"foo", "fa/f", "fA"}, "/fA/fb", assert.True, assert.False}, - {"Slice - none match", []string{"foo", "fa/f", "f"}, "/fA/fb", assert.False, assert.True}, - } - for _, test := range table { + for _, test := range pathComparisonsTable { suite.Run(test.name, func() { - t := suite.T() + var ( + t = suite.T() + f = filters.PathContains(test.targets) + nf = filters.NotPathContains(test.targets) + ) - f := filters.PathContains(test.targets) - nf := filters.NotPathContains(test.targets) - - test.expectF(t, f.Compare(test.input), "filter") - test.expectNF(t, nf.Compare(test.input), "negated filter") + test.expectContains.fn(t, f.Compare(test.input), "filter") + if test.expectContains.yes { + no.fn(t, nf.Compare(test.input), "negated filter") + } else { + yes.fn(t, nf.Compare(test.input), "negated filter") + } }) } } func (suite *FiltersSuite) TestPathContains_NormalizedTargets() { - table := []struct { - name string - targets []string - expect []string - }{ - {"Single - no slash", []string{"fA"}, []string{"/fA/"}}, - {"Single - pre slash", []string{"/fA"}, []string{"/fA/"}}, - {"Single - suff slash", []string{"fA/"}, []string{"/fA/"}}, - {"Single - both slashes", []string{"/fA/"}, []string{"/fA/"}}, - {"Multipath - no slash", []string{"fA/fB"}, []string{"/fA/fB/"}}, - {"Multipath - pre slash", []string{"/fA/fB"}, []string{"/fA/fB/"}}, - {"Multipath - suff slash", []string{"fA/fB/"}, []string{"/fA/fB/"}}, - {"Multipath - both slashes", []string{"/fA/fB/"}, []string{"/fA/fB/"}}, - {"Multi input - no slash", []string{"fA", "fB"}, []string{"/fA/", "/fB/"}}, - {"Multi input - pre slash", []string{"/fA", "/fB"}, []string{"/fA/", "/fB/"}}, - {"Multi input - suff slash", []string{"fA/", "fB/"}, []string{"/fA/", "/fB/"}}, - {"Multi input - both slashes", []string{"/fA/", "/fB/"}, []string{"/fA/", "/fB/"}}, - } - for _, test := range table { + for _, test := range pathElemNormalizationTable { suite.Run(test.name, func() { t := suite.T() @@ -464,76 +495,26 @@ func (suite *FiltersSuite) TestPathContains_NormalizedTargets() { } func (suite *FiltersSuite) TestPathSuffix() { - table := []struct { - name string - targets []string - input string - expectF assert.BoolAssertionFunc - expectNF assert.BoolAssertionFunc - }{ - {"Exact - same case", []string{"fA"}, "/fA", assert.True, assert.False}, - {"Exact - different case", []string{"fa"}, "/fA", assert.True, assert.False}, - {"Suffix - same case", []string{"fB"}, "/fA/fB", assert.True, assert.False}, - {"Suffix - different case", []string{"fb"}, "/fA/fB", assert.True, assert.False}, - {"Exact - multiple folders", []string{"fA/fB"}, "/fA/fB", assert.True, assert.False}, - {"Suffix - single folder partial", []string{"f"}, "/fA/fB", assert.False, assert.True}, - {"Suffix - multi folder partial", []string{"A/fB"}, "/fA/fB", assert.False, assert.True}, - {"Target Longer - single folder", []string{"fA"}, "/f", assert.False, assert.True}, - {"Target Longer - multi folder", []string{"fA/fB"}, "/fA/f", assert.False, assert.True}, - {"Not suffix - single folder", []string{"fA"}, "/af", assert.False, assert.True}, - {"Not suffix - multi folder", []string{"fA/fB"}, "/Af/fB", assert.False, assert.True}, - {"Exact - target variations - none", []string{"fA"}, "/fA", assert.True, assert.False}, - {"Exact - target variations - prefix", []string{"/fA"}, "/fA", assert.True, assert.False}, - {"Exact - target variations - suffix", []string{"fA/"}, "/fA", assert.True, assert.False}, - {"Exact - target variations - both", []string{"/fA/"}, "/fA", assert.True, assert.False}, - {"Exact - input variations - none", []string{"fA"}, "fA", assert.True, assert.False}, - {"Exact - input variations - prefix", []string{"fA"}, "/fA", assert.True, assert.False}, - {"Exact - input variations - suffix", []string{"fA"}, "fA/", assert.True, assert.False}, - {"Exact - input variations - both", []string{"fA"}, "/fA/", assert.True, assert.False}, - {"Suffix - target variations - none", []string{"fb"}, "/fA/fb", assert.True, assert.False}, - {"Suffix - target variations - prefix", []string{"/fb"}, "/fA/fb", assert.True, assert.False}, - {"Suffix - target variations - suffix", []string{"fb/"}, "/fA/fb", assert.True, assert.False}, - {"Suffix - target variations - both", []string{"/fb/"}, "/fA/fb", assert.True, assert.False}, - {"Suffix - input variations - none", []string{"fb"}, "fA/fb", assert.True, assert.False}, - {"Suffix - input variations - prefix", []string{"fb"}, "/fA/fb", assert.True, assert.False}, - {"Suffix - input variations - suffix", []string{"fb"}, "fA/fb/", assert.True, assert.False}, - {"Suffix - input variations - both", []string{"fb"}, "/fA/fb/", assert.True, assert.False}, - {"Slice - one matches", []string{"foo", "fa/f", "fb"}, "/fA/fb", assert.True, assert.False}, - {"Slice - none match", []string{"foo", "fa/f", "f"}, "/fA/fb", assert.False, assert.True}, - } - for _, test := range table { + for _, test := range pathComparisonsTable { suite.Run(test.name, func() { - t := suite.T() + var ( + t = suite.T() + f = filters.PathSuffix(test.targets) + nf = filters.NotPathSuffix(test.targets) + ) - f := filters.PathSuffix(test.targets) - nf := filters.NotPathSuffix(test.targets) - - test.expectF(t, f.Compare(test.input), "filter") - test.expectNF(t, nf.Compare(test.input), "negated filter") + test.expectSuffix.fn(t, f.Compare(test.input), "filter") + if test.expectSuffix.yes { + no.fn(t, nf.Compare(test.input), "negated filter") + } else { + yes.fn(t, nf.Compare(test.input), "negated filter") + } }) } } func (suite *FiltersSuite) TestPathSuffix_NormalizedTargets() { - table := []struct { - name string - targets []string - expect []string - }{ - {"Single - no slash", []string{"fA"}, []string{"/fA/"}}, - {"Single - pre slash", []string{"/fA"}, []string{"/fA/"}}, - {"Single - suff slash", []string{"fA/"}, []string{"/fA/"}}, - {"Single - both slashes", []string{"/fA/"}, []string{"/fA/"}}, - {"Multipath - no slash", []string{"fA/fB"}, []string{"/fA/fB/"}}, - {"Multipath - pre slash", []string{"/fA/fB"}, []string{"/fA/fB/"}}, - {"Multipath - suff slash", []string{"fA/fB/"}, []string{"/fA/fB/"}}, - {"Multipath - both slashes", []string{"/fA/fB/"}, []string{"/fA/fB/"}}, - {"Multi input - no slash", []string{"fA", "fB"}, []string{"/fA/", "/fB/"}}, - {"Multi input - pre slash", []string{"/fA", "/fB"}, []string{"/fA/", "/fB/"}}, - {"Multi input - suff slash", []string{"fA/", "fB/"}, []string{"/fA/", "/fB/"}}, - {"Multi input - both slashes", []string{"/fA/", "/fB/"}, []string{"/fA/", "/fB/"}}, - } - for _, test := range table { + for _, test := range pathElemNormalizationTable { suite.Run(test.name, func() { t := suite.T() @@ -544,67 +525,26 @@ func (suite *FiltersSuite) TestPathSuffix_NormalizedTargets() { } func (suite *FiltersSuite) TestPathEquals() { - table := []struct { - name string - targets []string - input string - expectF assert.BoolAssertionFunc - expectNF assert.BoolAssertionFunc - }{ - {"Exact - same case", []string{"fA"}, "/fA", assert.True, assert.False}, - {"Exact - different case", []string{"fa"}, "/fA", assert.True, assert.False}, - {"Exact - multiple folders", []string{"fA/fB"}, "/fA/fB", assert.True, assert.False}, - {"Exact - target variations - none", []string{"fA"}, "/fA", assert.True, assert.False}, - {"Exact - target variations - prefix", []string{"/fA"}, "/fA", assert.True, assert.False}, - {"Exact - target variations - suffix", []string{"fA/"}, "/fA", assert.True, assert.False}, - {"Exact - target variations - both", []string{"/fA/"}, "/fA", assert.True, assert.False}, - {"Exact - input variations - none", []string{"fA"}, "fA", assert.True, assert.False}, - {"Exact - input variations - prefix", []string{"fA"}, "/fA", assert.True, assert.False}, - {"Exact - input variations - suffix", []string{"fA"}, "fA/", assert.True, assert.False}, - {"Exact - input variations - both", []string{"fA"}, "/fA/", assert.True, assert.False}, - {"Partial match", []string{"f"}, "/fA/", assert.False, assert.True}, - {"Suffix - same case", []string{"fB"}, "/fA/fB", assert.False, assert.True}, - {"Suffix - different case", []string{"fb"}, "/fA/fB", assert.False, assert.True}, - {"Prefix - same case", []string{"fA"}, "/fA/fB", assert.False, assert.True}, - {"Prefix - different case", []string{"fa"}, "/fA/fB", assert.False, assert.True}, - {"Contains - same case", []string{"fB"}, "/fA/fB/fC", assert.False, assert.True}, - {"Contains - different case", []string{"fb"}, "/fA/fB/fC", assert.False, assert.True}, - {"Slice - one matches", []string{"foo", "/fA/fb", "fb"}, "/fA/fb", assert.True, assert.False}, - {"Slice - none match", []string{"foo", "fa/f", "f"}, "/fA/fb", assert.False, assert.True}, - } - for _, test := range table { + for _, test := range pathComparisonsTable { suite.Run(test.name, func() { - t := suite.T() + var ( + t = suite.T() + f = filters.PathEquals(test.targets) + nf = filters.NotPathEquals(test.targets) + ) - f := filters.PathEquals(test.targets) - nf := filters.NotPathEquals(test.targets) - - test.expectF(t, f.Compare(test.input), "filter") - test.expectNF(t, nf.Compare(test.input), "negated filter") + test.expectEquals.fn(t, f.Compare(test.input), "filter") + if test.expectEquals.yes { + no.fn(t, nf.Compare(test.input), "negated filter") + } else { + yes.fn(t, nf.Compare(test.input), "negated filter") + } }) } } func (suite *FiltersSuite) TestPathEquals_NormalizedTargets() { - table := []struct { - name string - targets []string - expect []string - }{ - {"Single - no slash", []string{"fA"}, []string{"/fA/"}}, - {"Single - pre slash", []string{"/fA"}, []string{"/fA/"}}, - {"Single - suff slash", []string{"fA/"}, []string{"/fA/"}}, - {"Single - both slashes", []string{"/fA/"}, []string{"/fA/"}}, - {"Multipath - no slash", []string{"fA/fB"}, []string{"/fA/fB/"}}, - {"Multipath - pre slash", []string{"/fA/fB"}, []string{"/fA/fB/"}}, - {"Multipath - suff slash", []string{"fA/fB/"}, []string{"/fA/fB/"}}, - {"Multipath - both slashes", []string{"/fA/fB/"}, []string{"/fA/fB/"}}, - {"Multi input - no slash", []string{"fA", "fB"}, []string{"/fA/", "/fB/"}}, - {"Multi input - pre slash", []string{"/fA", "/fB"}, []string{"/fA/", "/fB/"}}, - {"Multi input - suff slash", []string{"fA/", "fB/"}, []string{"/fA/", "/fB/"}}, - {"Multi input - both slashes", []string{"/fA/", "/fB/"}, []string{"/fA/", "/fB/"}}, - } - for _, test := range table { + for _, test := range pathElemNormalizationTable { suite.Run(test.name, func() { t := suite.T() @@ -614,6 +554,10 @@ func (suite *FiltersSuite) TestPathEquals_NormalizedTargets() { } } +// --------------------------------------------------------------------------- +// pii handling +// --------------------------------------------------------------------------- + func (suite *FiltersSuite) TestFilter_pii() { targets := []string{"fnords", "smarf", "*"} @@ -636,8 +580,8 @@ func (suite *FiltersSuite) TestFilter_pii() { suite.Run(test.name, func() { var ( t = suite.T() - expect = test.f.Comparator.String() + ":***,***,*" - expectPlain = test.f.Comparator.String() + ":" + strings.Join(targets, ",") + expect = string(test.f.Comparator) + ":***,***,*" + expectPlain = string(test.f.Comparator) + ":" + strings.Join(targets, ",") ) result := test.f.Conceal() @@ -671,14 +615,14 @@ func (suite *FiltersSuite) TestFilter_pii() { { "identity", filters.Identity("id"), - filters.IdentityValue.String() + ":***", - filters.IdentityValue.String() + ":id", + filters.IdentityValue + ":***", + filters.IdentityValue + ":id", }, { "identity", filters.Identity("*"), - filters.IdentityValue.String() + ":*", - filters.IdentityValue.String() + ":*", + filters.IdentityValue + ":*", + filters.IdentityValue + ":*", }, } for _, test := range table2 { diff --git a/src/pkg/selectors/scopes_test.go b/src/pkg/selectors/scopes_test.go index c4137bbdc..a70de3806 100644 --- a/src/pkg/selectors/scopes_test.go +++ b/src/pkg/selectors/scopes_test.go @@ -513,17 +513,17 @@ func (suite *SelectorScopesSuite) TestScopeConfig() { table := []struct { name string config scopeConfig - expect int + expect string }{ { name: "no configs set", config: scopeConfig{}, - expect: int(filters.EqualTo), + expect: filters.EqualTo, }, { name: "force prefix", config: scopeConfig{usePrefixFilter: true}, - expect: int(filters.TargetPrefixes), + expect: filters.TargetPrefixes, }, } for _, test := range table { @@ -531,7 +531,7 @@ func (suite *SelectorScopesSuite) TestScopeConfig() { t := suite.T() result := filterFor(test.config, input) - assert.Equal(t, test.expect, int(result.Comparator)) + assert.Equal(t, test.expect, string(result.Comparator)) }) } }