Skip to content

Commit

Permalink
Ability to filter with case insensitive tags (#2039)
Browse files Browse the repository at this point in the history
* Ability to filter with case in-sensitive tags
  • Loading branch information
haroon-sheikh authored Jul 9, 2021
1 parent c76b761 commit 763a652
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 19 deletions.
7 changes: 7 additions & 0 deletions env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const (
saveExecutionResult = "save_execution_result"
// CsvDelimiter holds delimiter used to parse csv files
CsvDelimiter = "csv_delimiter"
allowCaseSensitiveTags = "allow_case_sensitive_tags"
allowMultilineStep = "allow_multiline_step"
allowScenarioDatatable = "allow_scenario_datatable"
allowFilteredParallelExecution = "allow_filtered_parallel_execution"
Expand Down Expand Up @@ -115,6 +116,7 @@ func loadDefaultEnvVars() {
defaultScreenshotDir := filepath.Join(config.ProjectRoot, common.DotGauge, "screenshots")
addEnvVar(GaugeScreenshotsDir, defaultScreenshotDir)
addEnvVar(gaugeSpecFileExtensions, ".spec, .md")
addEnvVar(allowCaseSensitiveTags, "false")
err := os.MkdirAll(defaultScreenshotDir, 0750)
if err != nil {
logger.Warningf(true, "Could not create screenshot dir at %s", err.Error())
Expand Down Expand Up @@ -309,3 +311,8 @@ var GaugeSpecFileExtensions = func() []string {
}
return allowedExts
}

// AllowCaseSensitiveTags determines if the casing is ignored in tags filtering
var AllowCaseSensitiveTags = func() bool {
return convertToBool(allowCaseSensitiveTags, false)
}
1 change: 1 addition & 0 deletions env/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func (s *MySuite) TestLoadDefaultEnv(c *C) {
defaultScreenshotDir := filepath.Join(config.ProjectRoot, common.DotGauge, "screenshots")
c.Assert(os.Getenv("gauge_screenshots_dir"), Equals, defaultScreenshotDir)
c.Assert(os.Getenv("gauge_spec_file_extensions"), Equals, ".spec, .md")
c.Assert(os.Getenv("allow_case_sensitive_tags"), Equals, "false")
}

// If default env dir is present, the values present in there should overwrite
Expand Down
6 changes: 5 additions & 1 deletion filter/specItemFilter.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package filter

import (
"errors"
"github.com/getgauge/gauge/env"
"go/constant"
"go/token"
"go/types"
Expand Down Expand Up @@ -70,7 +71,10 @@ func sanitize(tag string) string {
if _, err := strconv.ParseBool(tag); err == nil {
return fmt.Sprintf("{%s}", tag)
}
return tag
if env.AllowCaseSensitiveTags() {
return tag
}
return strings.ToLower(tag)
}

func (filter *ScenarioFilterBasedOnTags) filterTags(stags []string) bool {
Expand Down
133 changes: 126 additions & 7 deletions filter/specItemFilter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package filter

import (
"os"
"testing"

"github.com/getgauge/gauge/gauge"
Expand All @@ -19,6 +20,15 @@ type MySuite struct{}

var _ = Suite(&MySuite{})

func before() {
os.Clearenv()
os.Setenv("allow_case_sensitive_tags", "false")
}

func after() {
os.Clearenv()
}

func (s *MySuite) TestToEvaluateTagExpressionWithTwoTags(c *C) {
filter := &ScenarioFilterBasedOnTags{tagExpression: "tag1 & tag3"}
c.Assert(filter.filterTags([]string{"tag1", "tag2"}), Equals, false)
Expand Down Expand Up @@ -314,12 +324,12 @@ func (s *MySuite) TestToEvaluateTagExpression(c *C) {
scenario1 := &gauge.Scenario{
Heading: &gauge.Heading{Value: "First Scenario"},
Span: &gauge.Span{Start: 1, End: 3},
Tags: &gauge.Tags{RawValues: [][]string{[]string{myTags[0]}}},
Tags: &gauge.Tags{RawValues: [][]string{{myTags[0]}}},
}
scenario2 := &gauge.Scenario{
Heading: &gauge.Heading{Value: "Second Scenario"},
Span: &gauge.Span{Start: 4, End: 6},
Tags: &gauge.Tags{RawValues: [][]string{[]string{"tag3"}}},
Tags: &gauge.Tags{RawValues: [][]string{{"tag3"}}},
}

scenario3 := &gauge.Scenario{
Expand Down Expand Up @@ -396,7 +406,7 @@ func (s *MySuite) TestToFilterMultipleScenariosByMultipleTags(c *C) {
scenario1 := &gauge.Scenario{
Heading: &gauge.Heading{Value: "First Scenario"},
Span: &gauge.Span{Start: 1, End: 3},
Tags: &gauge.Tags{RawValues: [][]string{[]string{"tag1"}}},
Tags: &gauge.Tags{RawValues: [][]string{{"tag1"}}},
}
scenario2 := &gauge.Scenario{
Heading: &gauge.Heading{Value: "Second Scenario"},
Expand All @@ -412,7 +422,7 @@ func (s *MySuite) TestToFilterMultipleScenariosByMultipleTags(c *C) {
scenario4 := &gauge.Scenario{
Heading: &gauge.Heading{Value: "Fourth Scenario"},
Span: &gauge.Span{Start: 4, End: 6},
Tags: &gauge.Tags{RawValues: [][]string{[]string{"prod", "tag7", "tag1", "tag2"}}},
Tags: &gauge.Tags{RawValues: [][]string{{"prod", "tag7", "tag1", "tag2"}}},
}
spec1 := &gauge.Specification{
Items: []gauge.Item{scenario1, scenario2, scenario3, scenario4},
Expand Down Expand Up @@ -488,13 +498,13 @@ func (s *MySuite) TestToFilterScenariosByTagExpWithDuplicateTagNames(c *C) {
scenario2 := &gauge.Scenario{
Heading: &gauge.Heading{Value: "Second Scenario"},
Span: &gauge.Span{Start: 4, End: 6},
Tags: &gauge.Tags{RawValues: [][]string{[]string{"tag1"}}},
Tags: &gauge.Tags{RawValues: [][]string{{"tag1"}}},
}

scenario3 := &gauge.Scenario{
Heading: &gauge.Heading{Value: "Third Scenario"},
Span: &gauge.Span{Start: 4, End: 6},
Tags: &gauge.Tags{RawValues: [][]string{[]string{"tag12"}}},
Tags: &gauge.Tags{RawValues: [][]string{{"tag12"}}},
}

spec1 := &gauge.Specification{
Expand Down Expand Up @@ -524,13 +534,31 @@ func (s *MySuite) TestFilterTags(c *C) {
c.Assert(evaluateTrue, Equals, true)
}

func (s *MySuite) TestFilterMixedCaseTags(c *C) {
before()
defer after()
specTags := []string{"abcd", "foo", "BAR", "foo bar"}
tagFilter := NewScenarioFilterBasedOnTags(specTags, "abcd & FOO bar")
evaluateTrue := tagFilter.filterTags(specTags)
c.Assert(evaluateTrue, Equals, true)
}

func (s *MySuite) TestSanitizeTags(c *C) {
specTags := []string{"abcd", "foo", "bar", "foo bar"}
tagFilter := NewScenarioFilterBasedOnTags(specTags, "abcd & foo bar | true")
evaluateTrue := tagFilter.filterTags(specTags)
c.Assert(evaluateTrue, Equals, true)
}

func (s *MySuite) TestSanitizeMixedCaseTags(c *C) {
before()
defer after()
specTags := []string{"abcd", "foo", "bar", "foo bar"}
tagFilter := NewScenarioFilterBasedOnTags(specTags, "abcd & foo Bar | true")
evaluateTrue := tagFilter.filterTags(specTags)
c.Assert(evaluateTrue, Equals, true)
}

func (s *MySuite) TestToFilterSpecsByTags(c *C) {
myTags := []string{"tag1", "tag2"}
scenario1 := &gauge.Scenario{
Expand Down Expand Up @@ -582,6 +610,59 @@ func (s *MySuite) TestToFilterSpecsByTags(c *C) {

}

func (s *MySuite) TestToFilterSpecsByMixedCaseTags(c *C) {
before()
defer after()
myTags := []string{"tag1", "TAG2"}
scenario1 := &gauge.Scenario{
Heading: &gauge.Heading{Value: "First Scenario"},
Span: &gauge.Span{Start: 1, End: 3},
Tags: &gauge.Tags{RawValues: [][]string{myTags}},
}
scenario2 := &gauge.Scenario{
Heading: &gauge.Heading{Value: "Second Scenario"},
Span: &gauge.Span{Start: 4, End: 6},
}
scenario3 := &gauge.Scenario{
Heading: &gauge.Heading{Value: "Third Scenario"},
Span: &gauge.Span{Start: 1, End: 3},
}

spec1 := &gauge.Specification{
Items: []gauge.Item{scenario1, scenario2},
Scenarios: []*gauge.Scenario{scenario1, scenario2},
}
spec2 := &gauge.Specification{
Items: []gauge.Item{scenario2, scenario3},
Scenarios: []*gauge.Scenario{scenario2, scenario3},
}

spec3 := &gauge.Specification{
Items: []gauge.Item{scenario1, scenario3},
Scenarios: []*gauge.Scenario{scenario1, scenario3},
}

var specs []*gauge.Specification
specs = append(specs, spec1, spec2, spec3)

filteredSpecs, otherSpecs := filterSpecsByTags(specs, "tag1 & Tag2")
c.Assert(len(filteredSpecs), Equals, 2)
c.Assert(len(filteredSpecs[0].Scenarios), Equals, 1)
c.Assert(len(filteredSpecs[1].Scenarios), Equals, 1)
c.Assert(filteredSpecs[0].Scenarios[0], Equals, scenario1)
c.Assert(filteredSpecs[1].Scenarios[0], Equals, scenario1)

c.Assert(len(otherSpecs), Equals, 3)
c.Assert(len(otherSpecs[0].Scenarios), Equals, 1)
c.Assert(len(otherSpecs[1].Scenarios), Equals, 2)
c.Assert(len(otherSpecs[2].Scenarios), Equals, 1)
c.Assert(otherSpecs[0].Scenarios[0], Equals, scenario2)
c.Assert(otherSpecs[1].Scenarios[0], Equals, scenario2)
c.Assert(otherSpecs[1].Scenarios[1], Equals, scenario3)
c.Assert(otherSpecs[2].Scenarios[0], Equals, scenario3)

}

func (s *MySuite) TestToFilterScenariosByTag(c *C) {
myTags := []string{"tag1", "tag2"}

Expand Down Expand Up @@ -618,13 +699,51 @@ func (s *MySuite) TestToFilterScenariosByTag(c *C) {
c.Assert(otherSpecs[0].Scenarios[1], Equals, scenario3)
}

func (s *MySuite) TestToFilterScenariosByMixedCaseTag(c *C) {
before()
defer after()
myTags := []string{"Tag-1", "tag2"}

scenario1 := &gauge.Scenario{
Heading: &gauge.Heading{Value: "First Scenario"},
Span: &gauge.Span{Start: 1, End: 3},
}
scenario2 := &gauge.Scenario{
Heading: &gauge.Heading{Value: "Second Scenario"},
Span: &gauge.Span{Start: 4, End: 6},
Tags: &gauge.Tags{RawValues: [][]string{myTags}},
}

scenario3 := &gauge.Scenario{
Heading: &gauge.Heading{Value: "Third Scenario"},
Span: &gauge.Span{Start: 4, End: 6},
}

spec1 := &gauge.Specification{
Items: []gauge.Item{scenario1, scenario2, scenario3},
Scenarios: []*gauge.Scenario{scenario1, scenario2, scenario3},
}

var specs []*gauge.Specification
specs = append(specs, spec1)

filteredSpecs, otherSpecs := filterSpecsByTags(specs, "tag-1 & tag2")
c.Assert(len(filteredSpecs[0].Scenarios), Equals, 1)
c.Assert(filteredSpecs[0].Scenarios[0], Equals, scenario2)

c.Assert(len(otherSpecs), Equals, 1)
c.Assert(len(otherSpecs[0].Scenarios), Equals, 2)
c.Assert(otherSpecs[0].Scenarios[0], Equals, scenario1)
c.Assert(otherSpecs[0].Scenarios[1], Equals, scenario3)
}

func (s *MySuite) TestToFilterMultipleScenariosByTags(c *C) {
myTags := []string{"tag1", "tag2"}

scenario1 := &gauge.Scenario{
Heading: &gauge.Heading{Value: "First Scenario"},
Span: &gauge.Span{Start: 1, End: 3},
Tags: &gauge.Tags{RawValues: [][]string{[]string{"tag1"}}},
Tags: &gauge.Tags{RawValues: [][]string{{"tag1"}}},
}
scenario2 := &gauge.Scenario{
Heading: &gauge.Heading{Value: "Second Scenario"},
Expand Down
4 changes: 2 additions & 2 deletions parser/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ func ParseSpecFiles(specFiles []string, conceptDictionary *gauge.ConceptDictiona
}

// ParseSpecs parses specs in the give directory and gives specification and pass/fail status, used in validation.
func ParseSpecs(args []string, conceptsDictionary *gauge.ConceptDictionary, buildErrors *gauge.BuildErrors) ([]*gauge.Specification, bool) {
specs, failed := parseSpecsInDirs(conceptsDictionary, args, buildErrors)
func ParseSpecs(specsToParse []string, conceptsDictionary *gauge.ConceptDictionary, buildErrors *gauge.BuildErrors) ([]*gauge.Specification, bool) {
specs, failed := parseSpecsInDirs(conceptsDictionary, specsToParse, buildErrors)
specsToExecute := order.Sort(filter.FilterSpecs(specs))
return specsToExecute, failed
}
Expand Down
18 changes: 9 additions & 9 deletions validation/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,21 +161,21 @@ func NewValidationResult(s *gauge.SpecCollection, errMap *gauge.BuildErrors, r r
}

// ValidateSpecs parses the specs, creates a new validator and call the runner to get the validation result.
func ValidateSpecs(args []string, debug bool) *ValidationResult {
func ValidateSpecs(specsToValidate []string, debug bool) *ValidationResult {
logger.Debug(true, "Parsing started.")
conceptDict, res, err := parser.ParseConcepts()
if err != nil {
logger.Fatalf(true, "Unable to parse : %s", err.Error())
}
errMap := gauge.NewBuildErrors()
s, specsFailed := parser.ParseSpecs(args, conceptDict, errMap)
specs, specsFailed := parser.ParseSpecs(specsToValidate, conceptDict, errMap)
logger.Debug(true, "Parsing completed.")
r := startAPI(debug)
vErrs := NewValidator(s, r, conceptDict).Validate()
errMap = getErrMap(errMap, vErrs)
s = parser.GetSpecsForDataTableRows(s, errMap)
printValidationFailures(vErrs)
showSuggestion(vErrs)
validationErrors := NewValidator(specs, r, conceptDict).Validate()
errMap = getErrMap(errMap, validationErrors)
specs = parser.GetSpecsForDataTableRows(specs, errMap)
printValidationFailures(validationErrors)
showSuggestion(validationErrors)
if !res.Ok {
err := r.Kill()
if err != nil {
Expand All @@ -184,9 +184,9 @@ func ValidateSpecs(args []string, debug bool) *ValidationResult {
return NewValidationResult(nil, nil, nil, false, errors.New("Parsing failed"))
}
if specsFailed {
return NewValidationResult(gauge.NewSpecCollection(s, false), errMap, r, false)
return NewValidationResult(gauge.NewSpecCollection(specs, false), errMap, r, false)
}
return NewValidationResult(gauge.NewSpecCollection(s, false), errMap, r, true)
return NewValidationResult(gauge.NewSpecCollection(specs, false), errMap, r, true)
}

func getErrMap(errMap *gauge.BuildErrors, validationErrors validationErrors) *gauge.BuildErrors {
Expand Down

0 comments on commit 763a652

Please sign in to comment.