From e38c6ed719276480b3ad87f726126b98ccb63893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20L=C3=B6nnblad?= Date: Tue, 30 Jun 2020 22:44:00 +0200 Subject: [PATCH] Added an internal package for tags filtering --- .circleci/config.yml | 5 ++- internal/tags/tag_filter.go | 62 ++++++++++++++++++++++++++++++++ internal/tags/tag_filter_test.go | 51 ++++++++++++++++++++++++++ parser.go | 20 +++-------- suite_context_test.go | 8 +++-- tag_filter.go | 42 ---------------------- tag_filter_test.go | 33 ----------------- 7 files changed, 124 insertions(+), 97 deletions(-) create mode 100644 internal/tags/tag_filter.go create mode 100644 internal/tags/tag_filter_test.go delete mode 100644 tag_filter.go delete mode 100644 tag_filter_test.go diff --git a/.circleci/config.yml b/.circleci/config.yml index f6e9524..fc17772 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,13 +32,12 @@ commands: vet: description: "Run go vet" steps: - - run: go vet github.com/cucumber/godog - - run: go vet github.com/cucumber/godog/colors + - run: go vet ./... go_test: description: "Run go test" steps: - run: sed -i 's#github.com/cucumber/godog_test#_test#g' formatter-tests/*/* - - run: go test -v -race -coverprofile=coverage.txt -covermode=atomic + - run: go test -v -race -coverprofile=coverage.txt -covermode=atomic ./... godog: description: "Run godog" steps: diff --git a/internal/tags/tag_filter.go b/internal/tags/tag_filter.go new file mode 100644 index 0000000..5332545 --- /dev/null +++ b/internal/tags/tag_filter.go @@ -0,0 +1,62 @@ +package tags + +import ( + "strings" + + "github.com/cucumber/messages-go/v10" +) + +// ApplyTagFilter will apply a filter string on the +// array of pickles and returned the filtered list. +func ApplyTagFilter(filter string, pickles []*messages.Pickle) []*messages.Pickle { + if filter == "" { + return pickles + } + + var result = []*messages.Pickle{} + + for _, pickle := range pickles { + if match(filter, pickle.Tags) { + result = append(result, pickle) + } + } + + return result +} + +// Based on http://behat.readthedocs.org/en/v2.5/guides/6.cli.html#gherkin-filters +func match(filter string, tags []*messages.Pickle_PickleTag) (ok bool) { + ok = true + + for _, andTags := range strings.Split(filter, "&&") { + var okComma bool + + for _, tag := range strings.Split(andTags, ",") { + tag = strings.TrimSpace(tag) + tag = strings.Replace(tag, "@", "", -1) + + okComma = contains(tags, tag) || okComma + + if tag[0] == '~' { + tag = tag[1:] + okComma = !contains(tags, tag) || okComma + } + } + + ok = ok && okComma + } + + return +} + +func contains(tags []*messages.Pickle_PickleTag, tag string) bool { + for _, t := range tags { + tagName := strings.Replace(t.Name, "@", "", -1) + + if tagName == tag { + return true + } + } + + return false +} diff --git a/internal/tags/tag_filter_test.go b/internal/tags/tag_filter_test.go new file mode 100644 index 0000000..70798c0 --- /dev/null +++ b/internal/tags/tag_filter_test.go @@ -0,0 +1,51 @@ +package tags_test + +import ( + "testing" + + "github.com/cucumber/messages-go/v10" + "github.com/stretchr/testify/assert" + + "github.com/cucumber/godog/internal/tags" +) + +type tag = messages.Pickle_PickleTag +type pickle = messages.Pickle + +type testcase struct { + filter string + expected []*pickle +} + +var testdata = []*pickle{p1, p2, p3} +var p1 = &pickle{Id: "one", Tags: []*tag{{Name: "@one"}, {Name: "@wip"}}} +var p2 = &pickle{Id: "two", Tags: []*tag{{Name: "@two"}, {Name: "@wip"}}} +var p3 = &pickle{Id: "three", Tags: []*tag{{Name: "@hree"}, {Name: "@wip"}}} + +var testcases = []testcase{ + {filter: "", expected: testdata}, + + {filter: "@one", expected: []*pickle{p1}}, + {filter: "~@one", expected: []*pickle{p2, p3}}, + {filter: "one", expected: []*pickle{p1}}, + {filter: " one ", expected: []*pickle{p1}}, + + {filter: "@one,@two", expected: []*pickle{p1, p2}}, + {filter: "@one,~@two", expected: []*pickle{p1, p3}}, + {filter: " @one , @two ", expected: []*pickle{p1, p2}}, + + {filter: "@one&&@two", expected: []*pickle{}}, + {filter: "@one&&~@two", expected: []*pickle{p1}}, + {filter: "@one&&@wip", expected: []*pickle{p1}}, + + {filter: "@one&&@two,@wip", expected: []*pickle{p1}}, +} + +func Test_ApplyTagFilter(t *testing.T) { + for _, tc := range testcases { + t.Run("", func(t *testing.T) { + actual := tags.ApplyTagFilter(tc.filter, testdata) + assert.Equal(t, tc.expected, actual) + }) + } +} diff --git a/parser.go b/parser.go index e0b51b0..2824e35 100644 --- a/parser.go +++ b/parser.go @@ -12,6 +12,8 @@ import ( "github.com/cucumber/gherkin-go/v11" "github.com/cucumber/messages-go/v10" + + "github.com/cucumber/godog/internal/tags" ) var pathLineRe = regexp.MustCompile(`:([\d]+)$`) @@ -149,9 +151,9 @@ func parseFeatures(filter string, paths []string) ([]*feature, error) { return features, nil } -func filterFeatures(tags string, features []*feature) (result []*feature) { +func filterFeatures(filter string, features []*feature) (result []*feature) { for _, ft := range features { - ft.pickles = applyTagFilter(tags, ft.pickles) + ft.pickles = tags.ApplyTagFilter(filter, ft.pickles) if ft.Feature != nil && len(ft.pickles) > 0 { result = append(result, ft) @@ -160,17 +162,3 @@ func filterFeatures(tags string, features []*feature) (result []*feature) { return } - -func applyTagFilter(tags string, pickles []*messages.Pickle) (result []*messages.Pickle) { - if len(tags) == 0 { - return pickles - } - - for _, pickle := range pickles { - if matchesTags(tags, pickle.Tags) { - result = append(result, pickle) - } - } - - return -} diff --git a/suite_context_test.go b/suite_context_test.go index bc91b00..f7952f8 100644 --- a/suite_context_test.go +++ b/suite_context_test.go @@ -11,9 +11,11 @@ import ( "strings" "github.com/cucumber/gherkin-go/v11" - "github.com/cucumber/godog/colors" "github.com/cucumber/messages-go/v10" "github.com/stretchr/testify/assert" + + "github.com/cucumber/godog/colors" + "github.com/cucumber/godog/internal/tags" ) // InitializeScenario provides steps for godog suite execution and @@ -180,13 +182,13 @@ func (tc *godogFeaturesScenario) iRunFeatureSuiteWithFormatter(name string) erro return tc.iRunFeatureSuiteWithTagsAndFormatter("", f) } -func (tc *godogFeaturesScenario) iRunFeatureSuiteWithTagsAndFormatter(tags string, fmtFunc FormatterFunc) error { +func (tc *godogFeaturesScenario) iRunFeatureSuiteWithTagsAndFormatter(filter string, fmtFunc FormatterFunc) error { if err := tc.parseFeatures(); err != nil { return err } for _, feat := range tc.features { - feat.pickles = applyTagFilter(tags, feat.pickles) + feat.pickles = tags.ApplyTagFilter(filter, feat.pickles) } tc.testedSuite.storage = newStorage() diff --git a/tag_filter.go b/tag_filter.go deleted file mode 100644 index 3b95abc..0000000 --- a/tag_filter.go +++ /dev/null @@ -1,42 +0,0 @@ -package godog - -import ( - "strings" - - "github.com/cucumber/messages-go/v10" -) - -// based on http://behat.readthedocs.org/en/v2.5/guides/6.cli.html#gherkin-filters -func matchesTags(filter string, tags []*messages.Pickle_PickleTag) (ok bool) { - ok = true - - for _, andTags := range strings.Split(filter, "&&") { - var okComma bool - - for _, tag := range strings.Split(andTags, ",") { - tag = strings.Replace(strings.TrimSpace(tag), "@", "", -1) - - okComma = hasTag(tags, tag) || okComma - if tag[0] == '~' { - tag = tag[1:] - okComma = !hasTag(tags, tag) || okComma - } - } - - ok = ok && okComma - } - - return -} - -func hasTag(tags []*messages.Pickle_PickleTag, tag string) bool { - for _, t := range tags { - tName := strings.Replace(t.Name, "@", "", -1) - - if tName == tag { - return true - } - } - - return false -} diff --git a/tag_filter_test.go b/tag_filter_test.go deleted file mode 100644 index f29b6ef..0000000 --- a/tag_filter_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package godog - -import ( - "testing" - - "github.com/cucumber/messages-go/v10" -) - -func assertNotMatchesTagFilter(tags []*tag, filter string, t *testing.T) { - if matchesTags(filter, tags) { - t.Errorf(`expected tags: %v not to match tag filter "%s", but it did`, tags, filter) - } -} - -func assertMatchesTagFilter(tags []*tag, filter string, t *testing.T) { - if !matchesTags(filter, tags) { - t.Errorf(`expected tags: %v to match tag filter "%s", but it did not`, tags, filter) - } -} - -func TestTagFilter(t *testing.T) { - assertMatchesTagFilter([]*tag{{Name: "wip"}}, "@wip", t) - assertMatchesTagFilter([]*tag{}, "~@wip", t) - assertMatchesTagFilter([]*tag{{Name: "one"}, {Name: "two"}}, "@two,@three", t) - assertMatchesTagFilter([]*tag{{Name: "one"}, {Name: "two"}}, "@one&&@two", t) - assertMatchesTagFilter([]*tag{{Name: "one"}, {Name: "two"}}, "one && two", t) - - assertNotMatchesTagFilter([]*tag{}, "@wip", t) - assertNotMatchesTagFilter([]*tag{{Name: "one"}, {Name: "two"}}, "@one&&~@two", t) - assertNotMatchesTagFilter([]*tag{{Name: "one"}, {Name: "two"}}, "@one && ~@two", t) -} - -type tag = messages.Pickle_PickleTag