diff --git a/internal/filter/filter_test.go b/internal/filter/filter_test.go new file mode 100644 index 000000000..aa7048edf --- /dev/null +++ b/internal/filter/filter_test.go @@ -0,0 +1,140 @@ +package filter + +import ( + "errors" + "github.com/stretchr/testify/assert" + "regexp" + "strings" + "testing" +) + +const unknown string = "unknown" + +var evalError = errors.New("evaluation error") + +func TestFilter(t *testing.T) { + t.Parallel() + + filterable := &filterableType{ + key: "domain", + value: "example.com", + } + + t.Run("InvalidOperator", func(t *testing.T) { + chain, err := NewChain("unknown", nil) + assert.Nil(t, chain) + assert.EqualError(t, err, "invalid logical operator provided: \"unknown\"") + + condition, err := NewCondition("column", "unknown", "value") + assert.Nil(t, condition) + assert.EqualError(t, err, "invalid comparison operator provided: \"unknown\"") + }) + + t.Run("EvaluationError", func(t *testing.T) { + t.Parallel() + + testInvalidData := []struct { + Expression string + }{ + {"domain=" + unknown}, + {"domain!=" + unknown}, + {"domain<" + unknown}, + {"domain<=" + unknown}, + {"domain>" + unknown}, + {"domain>=" + unknown}, + {"domain~" + unknown}, + {"domain!~" + unknown}, + {"!(domain!=" + unknown + ")"}, + {"domain=" + unknown + "&domain<=test.example.com"}, + {"domain<=" + unknown + "|domain<=test.example.com"}, + } + + for _, td := range testInvalidData { + f, err := Parse(td.Expression) + assert.NoError(t, err) + + matched, err := f.Eval(filterable) + assert.EqualError(t, err, evalError.Error()) + assert.Equal(t, matched, false, "unexpected filter result for %q", td.Expression) + } + }) + + t.Run("EvaluateFilter", func(t *testing.T) { + t.Parallel() + + testdata := []struct { + Expression string + Expected bool + }{ + {"domain=example.com", true}, + {"domain!=example.com", false}, + {"domain=test.example.com", false}, + {"name!=example.com", false}, + {"domain", true}, + {"name", false}, + {"display_name", false}, + {"!name", true}, + {"domain~example*", true}, + {"domain!~example*", false}, + {"domain~example*&!domain", false}, + {"domain>a", true}, + {"domainz", false}, + {"domain=example&domain<=test.example.com", true}, + {"domain<=example|domain<=test.example.com", true}, + {"domain<=example|domain>=test.example.com", false}, + } + + for _, td := range testdata { + f, err := Parse(td.Expression) + if assert.NoError(t, err, "parsing %q should not return an error", td.Expression) { + matched, err := f.Eval(filterable) + assert.NoError(t, err) + assert.Equal(t, td.Expected, matched, "unexpected filter result for %q", td.Expression) + } + } + }) +} + +type filterableType struct { + key string + value string +} + +func (f *filterableType) EvalEqual(_ string, value string) (bool, error) { + if value == unknown { + return false, evalError + } + + return strings.EqualFold(f.value, value), nil +} + +func (f *filterableType) EvalLess(_ string, value string) (bool, error) { + if value == unknown { + return false, evalError + } + + return f.value < value, nil +} + +func (f *filterableType) EvalLike(_ string, value string) (bool, error) { + if value == unknown { + return false, evalError + } + + regex := regexp.MustCompile("^example.*$") + return regex.MatchString(f.value), nil +} + +func (f *filterableType) EvalLessOrEqual(_ string, value string) (bool, error) { + if value == unknown { + return false, evalError + } + + return f.value <= value, nil +} + +func (f *filterableType) EvalExists(key string) bool { + return f.key == key +}