Skip to content

Commit

Permalink
Allow exclusionary tags to omit scenarios
Browse files Browse the repository at this point in the history
If a user passes in a tag for which no scenario should run, e.g.
   --tag=-A

then the expectation is that no scenario with that tag would run.
However, the previous behavior was to a scenario with an inclusionary
tag regardless of the exclusionary tag. For example, if a scenario's
tags were:

   ['A', 'B]

and the user specified:

   --tag=-A --tag=B

the scenario would run.

This change changes the behavior of scenario filtering:
1) If an exclusionary tag matches the scenario is rejected.
2) If an inclusionary tag matches the scenario is accepted.
3) If a tag with ~ matches then it is accepted with some probability

gabrielfalcao#498
  • Loading branch information
brarcher committed Nov 22, 2016
1 parent 70f20f4 commit 5698979
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 15 deletions.
45 changes: 30 additions & 15 deletions lettuce/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -647,30 +647,39 @@ def matches_tags(self, tags):
if tags is None:
return True

has_exclusionary_tags = any([t.startswith('-') for t in tags])
exclusionary_tags = [t[1:] for t in tags if t.startswith('-') and not t.startswith('-~')]
inclusionary_tags = [t for t in tags if not t.startswith('-') and not t.startswith('~')]

if not self.tags and not has_exclusionary_tags:
return False
if not isinstance(self.tags, list):
self.tags = []

matched = []
# If there are inclusionary tags, at least one must match
if len(inclusionary_tags) > 0:
matches = set(self.tags).intersection(inclusionary_tags)
if len(matches) == 0:
# This scenario did not match any of the inclusionary
# tags, and it must be excluded
return False

# If there are exclusionary tags, if any match the scenario must
# be thrown out
if len(exclusionary_tags) > 0:
matches = set(self.tags).intersection(exclusionary_tags)
if len(matches) > 0:
# At least one exclusionary tag matches, omit the
# scenario
return False

if isinstance(self.tags, list):
for tag in self.tags:
if tag in tags:
return True
else:
self.tags = []
matched = []

for tag in tags:
exclude = tag.startswith('-')
if exclude:
tag = tag[1:]

fuzzable = tag.startswith('~')
if fuzzable:
tag = tag[1:]

result = tag in self.tags
if fuzzable:
fuzzed = []
for internal_tag in self.tags:
Expand All @@ -679,14 +688,20 @@ def matches_tags(self, tags):
fuzzed.append(ratio <= 80)
else:
fuzzed.append(ratio > 80)

result = any(fuzzed)
matched.append(result)
elif exclude:
result = tag not in self.tags
matched.append(result)

matched.append(result)
# Determine if any tags may optionally be included.
# If so, all must fail for the scenario to be omitted
if not all(matched):
return False

return all(matched)
# If the check make it here, there is no reason to
# disclude the test
return True

@property
def evaluated(self):
Expand Down
12 changes: 12 additions & 0 deletions tests/unit/test_scenario_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,18 @@ def test_scenario_matches_tags_excluding_when_scenario_has_no_tags():

assert scenario.matches_tags(['-nope', '-neither'])

def test_scenario_matches_tags_both_include_and_exclude_tags():
("When Scenario#matches_tags is called for a scenario "
"that has an inclusionary and exclusionary tag that matches, "
"and expects the scenario to not match")

scenario = Scenario.from_string(
SCENARIO1,
original_string=SCENARIO1.strip(),
tags=['tag1', 'tag2'])

assert not scenario.matches_tags(['tag1', '-tag2'])


def test_scenario_matches_tags_excluding_fuzzywuzzy():
("When Scenario#matches_tags is called with a member starting with -~ "
Expand Down

0 comments on commit 5698979

Please sign in to comment.