add suffix and pathSuffix filters (#1659)
## Description Preparing for handling sharepoint webUrl selectors, we will need suffix-matching filters. ## Type of change - [x] 🌻 Feature ## Issue(s) * #1616 ## Test Plan - [x] ⚡ Unit test
This commit is contained in:
parent
34832591ce
commit
34ba06cf61
@ -28,10 +28,14 @@ const (
|
||||
IdentityValue
|
||||
// "foo" is a prefix of "foobarbaz"
|
||||
TargetPrefixes
|
||||
// "baz" is a suffix of "foobarbaz"
|
||||
TargetSuffixes
|
||||
// "foo" equals any complete element prefix of "foo/bar/baz"
|
||||
TargetPathPrefix
|
||||
// "foo" equals any complete element in "foo/bar/baz"
|
||||
TargetPathContains
|
||||
// "baz" equals any complete element suffix of "foo/bar/baz"
|
||||
TargetPathSuffix
|
||||
)
|
||||
|
||||
func norm(s string) string {
|
||||
@ -161,6 +165,18 @@ func NotPrefix(target string) Filter {
|
||||
return newFilter(TargetPrefixes, target, true)
|
||||
}
|
||||
|
||||
// Suffix creates a filter where Compare(v) is true if
|
||||
// target.Suffix(v)
|
||||
func Suffix(target string) Filter {
|
||||
return newFilter(TargetSuffixes, target, false)
|
||||
}
|
||||
|
||||
// NotSuffix creates a filter where Compare(v) is true if
|
||||
// !target.Suffix(v)
|
||||
func NotSuffix(target string) Filter {
|
||||
return newFilter(TargetSuffixes, target, true)
|
||||
}
|
||||
|
||||
// PathPrefix creates a filter where Compare(v) is true if
|
||||
// target.Prefix(v) &&
|
||||
// split(target)[i].Equals(split(v)[i]) for _all_ i in 0..len(target)-1
|
||||
@ -241,6 +257,44 @@ func NotPathContains(targets []string) Filter {
|
||||
return newSliceFilter(TargetPathContains, targets, tgts, true)
|
||||
}
|
||||
|
||||
// PathSuffix creates a filter where Compare(v) is true if
|
||||
// target.Suffix(v) &&
|
||||
// split(target)[i].Equals(split(v)[i]) for _all_ i in 0..len(target)-1
|
||||
// ex: target "/bar/baz" returns true for input "/foo/bar/baz",
|
||||
// but false for "/foobar/baz"
|
||||
//
|
||||
// Unlike single-target filters, this filter accepts a
|
||||
// slice of targets, will compare an input against each target
|
||||
// independently, and returns true if one or more of the
|
||||
// comparisons succeed.
|
||||
func PathSuffix(targets []string) Filter {
|
||||
tgts := make([]string, len(targets))
|
||||
for i := range targets {
|
||||
tgts[i] = normPathElem(targets[i])
|
||||
}
|
||||
|
||||
return newSliceFilter(TargetPathSuffix, targets, tgts, false)
|
||||
}
|
||||
|
||||
// NotPathSuffix creates a filter where Compare(v) is true if
|
||||
// !target.Suffix(v) ||
|
||||
// !split(target)[i].Equals(split(v)[i]) for _any_ i in 0..len(target)-1
|
||||
// ex: target "/bar/baz" returns false for input "/foo/bar/baz",
|
||||
// but true for "/foobar/baz"
|
||||
//
|
||||
// Unlike single-target filters, this filter accepts a
|
||||
// slice of targets, will compare an input against each target
|
||||
// independently, and returns true if one or more of the
|
||||
// comparisons succeed.
|
||||
func NotPathSuffix(targets []string) Filter {
|
||||
tgts := make([]string, len(targets))
|
||||
for i := range targets {
|
||||
tgts[i] = normPathElem(targets[i])
|
||||
}
|
||||
|
||||
return newSliceFilter(TargetPathSuffix, targets, tgts, true)
|
||||
}
|
||||
|
||||
// newFilter is the standard filter constructor.
|
||||
func newFilter(c comparator, target string, negate bool) Filter {
|
||||
return Filter{
|
||||
@ -302,12 +356,17 @@ func (f Filter) Compare(input string) bool {
|
||||
cmp = in
|
||||
case TargetPrefixes:
|
||||
cmp = prefixed
|
||||
case TargetSuffixes:
|
||||
cmp = suffixed
|
||||
case TargetPathPrefix:
|
||||
cmp = pathPrefix
|
||||
hasSlice = true
|
||||
case TargetPathContains:
|
||||
cmp = pathContains
|
||||
hasSlice = true
|
||||
case TargetPathSuffix:
|
||||
cmp = pathSuffix
|
||||
hasSlice = true
|
||||
case Passes:
|
||||
return true
|
||||
case Fails:
|
||||
@ -364,6 +423,11 @@ func prefixed(target, input string) bool {
|
||||
return strings.HasPrefix(input, target)
|
||||
}
|
||||
|
||||
// true if target has input as a suffix.
|
||||
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
|
||||
@ -393,6 +457,20 @@ 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)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
@ -405,8 +483,10 @@ var prefixString = map[comparator]string{
|
||||
TargetContains: "cont:",
|
||||
TargetIn: "in:",
|
||||
TargetPrefixes: "pfx:",
|
||||
TargetSuffixes: "sfx:",
|
||||
TargetPathPrefix: "pathPfx:",
|
||||
TargetPathContains: "pathCont:",
|
||||
TargetPathSuffix: "pathSfx:",
|
||||
}
|
||||
|
||||
func (f Filter) String() string {
|
||||
|
||||
@ -206,6 +206,31 @@ func (suite *FiltersSuite) TestPrefixes() {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *FiltersSuite) TestSuffixes() {
|
||||
target := "folderB"
|
||||
f := filters.Suffix(target)
|
||||
nf := filters.NotSuffix(target)
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
input string
|
||||
expectF assert.BoolAssertionFunc
|
||||
expectNF assert.BoolAssertionFunc
|
||||
}{
|
||||
{"Exact match - same case", "folderB", assert.True, assert.False},
|
||||
{"Exact match - different case", "Folderb", assert.True, assert.False},
|
||||
{"Suffix match - same case", "folderA/folderB", assert.True, assert.False},
|
||||
{"Suffix match - different case", "Foldera/folderb", assert.True, assert.False},
|
||||
{"Should not match substring", "folderB/folder1", assert.False, assert.True},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
test.expectF(t, f.Compare(test.input), "filter")
|
||||
test.expectNF(t, nf.Compare(test.input), "negated filter")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *FiltersSuite) TestPathPrefix() {
|
||||
table := []struct {
|
||||
name string
|
||||
@ -360,3 +385,79 @@ 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.True},
|
||||
{"Slice - none match", []string{"foo", "fa/f", "f"}, "/fA/fb", assert.False, assert.True},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
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")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
f := filters.PathSuffix(test.targets)
|
||||
assert.Equal(t, test.expect, f.NormalizedTargets)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user