# Copyright 2008-2015 Nokia Networks
# Copyright 2016- Robot Framework Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Sequence, TYPE_CHECKING
from robot.utils import setter
from .tags import TagPatterns
from .namepatterns import NamePatterns
from .visitor import SuiteVisitor
if TYPE_CHECKING:
from .keyword import Keyword
from .testcase import TestCase
from .testsuite import TestSuite
[docs]
class EmptySuiteRemover(SuiteVisitor):
def __init__(self, preserve_direct_children: bool = False):
self.preserve_direct_children = preserve_direct_children
[docs]
def end_suite(self, suite: 'TestSuite'):
if suite.parent or not self.preserve_direct_children:
suite.suites = [s for s in suite.suites if s.test_count]
[docs]
def visit_test(self, test: 'TestCase'):
pass
[docs]
def visit_keyword(self, keyword: 'Keyword'):
pass
[docs]
class Filter(EmptySuiteRemover):
def __init__(self,
include_suites: 'NamePatterns|Sequence[str]|None' = None,
include_tests: 'NamePatterns|Sequence[str]|None' = None,
include_tags: 'TagPatterns|Sequence[str]|None' = None,
exclude_tags: 'TagPatterns|Sequence[str]|None' = None):
super().__init__()
self.include_suites = include_suites
self.include_tests = include_tests
self.include_tags = include_tags
self.exclude_tags = exclude_tags
@setter
def include_suites(self, suites) -> 'NamePatterns|None':
return self._patterns_or_none(suites, NamePatterns)
@setter
def include_tests(self, tests) -> 'NamePatterns|None':
return self._patterns_or_none(tests, NamePatterns)
@setter
def include_tags(self, tags) -> 'TagPatterns|None':
return self._patterns_or_none(tags, TagPatterns)
@setter
def exclude_tags(self, tags) -> 'TagPatterns|None':
return self._patterns_or_none(tags, TagPatterns)
def _patterns_or_none(self, items, pattern_class):
if items is None or isinstance(items, pattern_class):
return items
return pattern_class(items)
[docs]
def start_suite(self, suite: 'TestSuite'):
if not self:
return False
if hasattr(suite, 'start_time'):
suite.start_time = suite.end_time = suite.elapsed_time = None
if self.include_suites is not None:
return self._filter_based_on_suite_name(suite)
suite.tests = [t for t in suite.tests if self._test_included(t)]
return bool(suite.suites)
def _filter_based_on_suite_name(self, suite: 'TestSuite') -> bool:
if self.include_suites.match(suite.name, suite.full_name):
suite.visit(Filter(include_tests=self.include_tests,
include_tags=self.include_tags,
exclude_tags=self.exclude_tags))
return False
suite.tests = []
return True
def _test_included(self, test: 'TestCase') -> bool:
tests, include, exclude \
= self.include_tests, self.include_tags, self.exclude_tags
if exclude is not None and exclude.match(test.tags):
return False
if include is not None and include.match(test.tags):
return True
if tests is not None and tests.match(test.name, test.full_name):
return True
return include is None and tests is None
def __bool__(self) -> bool:
return bool(self.include_suites is not None or
self.include_tests is not None or
self.include_tags is not None or
self.exclude_tags is not None)