Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exclude tag excludes even if an include tag matches #542

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ all: check_dependencies unit functional doctest
filename=lettuce-`python -c 'import lettuce;print lettuce.version'`.tar.gz

export PYTHONPATH:= ${PWD}
export LETTUCE_DEPENDENCIES:= nose mox sphinx lxml django fuzzywuzzy mock
export LETTUCE_DEPENDENCIES:= nose mox sphinx lxml django fuzzywuzzy mock python-subunit sure

check_dependencies:
@echo "Checking for dependencies to run tests ..."
Expand Down
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, "
"the scenario is excluded")

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