filters cleanup prep for case handling (#3395)

Some tidying up in filters before adding a case specific comparator.  Goals include:
* better test handling/coverage
* swap iota for string in comparator type
* more organized param normalization
* reduction in code duplication

---

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

- [x]  No

#### Type of change

- [x] 🧹 Tech Debt/Cleanup

#### Issue(s)

* #3313

#### Test Plan

- [x]  Unit test
- [x] 💚 E2E
This commit is contained in:
Keepers 2023-05-16 10:41:39 -06:00 committed by GitHub
parent 694abfab68
commit 5ca595b7b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 293 additions and 390 deletions

View File

@ -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]]
}

View File

@ -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
@ -93,6 +103,7 @@ type Filter struct {
// deprecated, kept around for deserialization
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
}

View File

@ -50,6 +50,8 @@ func (suite *FiltersSuite) TestEquals() {
expectF assert.BoolAssertionFunc
expectNF assert.BoolAssertionFunc
}{
{"foo", assert.True, assert.False},
{"FOO", assert.True, assert.False},
{" foo ", assert.True, assert.False},
{"bar", assert.False, assert.True},
}
@ -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 {
// ---------------------------------------------------------------------------
// 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,
}
no = baf{
fn: assert.False,
yes: false,
}
)
var pathComparisonsTable = []struct {
name string
targets []string
input string
expectF assert.BoolAssertionFunc
expectNF assert.BoolAssertionFunc
expectContains baf
expectEquals baf
expectPrefix baf
expectSuffix baf
}{
{"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},
{"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},
}
for _, test := range table {
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 {

View File

@ -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))
})
}
}