[Piglit] [PATCH v4 16/27] framework: Pull {include, exclude}_filter out of Options
Alejandro PiƱeiro
apinheiro at igalia.com
Wed Nov 16 08:17:55 UTC 2016
Hi Dylan,
On 09/11/16 21:53, Dylan Baker wrote:
> Since these are also just special cases of filters for the standard
> TestProfile filtering mechanism, and they have a lot of unique classes.
> This is just a waste, the same can be achieved with a much simpler class
> structure.
>
> Signed-off-by: Dylan Baker <dylanx.c.baker at intel.com>
Since this patch (commit e92555 on master) -t filtering doesn't work
fine for all the deqp based profiles.
For example:
./piglit run --overwrite tests/deqp_gles31.py -t
dEQP-GLES31.functional.shaders.builtin_functions.common.sign.int_lowp_tess_eval
results/deqp-test
or
./piglit run --overwrite tests/cts_gl45.py -t GL45-CTS.gtf32.*
results/20161114-test
Fails because they got an empty test list. As far as I see it works fine
with the tests/all.py profiles.
FWIW, this was somewhat hard to triagge, as since commit 0cd690 instead
of getting a "Fatal Error: There are no tests scheduled to run. Aborting
run." error message, it raises an assertion (assert data['tests'] at
json.py, line 155).
I started to take a look to it, but I will not be able to work on it, as
I will be on holidays until next Monday. If you prefer, I can open a bug
on the freedesktop bugzilla, so you can track it easily.
BR
> ---
> framework/options.py | 137 +----------------------
> framework/profile.py | 54 +++++---
> framework/programs/print_commands.py | 10 +-
> framework/programs/run.py | 30 +++--
> framework/summary/feature.py | 20 +--
> unittests/framework/test_options.py | 178 +----------------------------
> unittests/framework/test_profile.py | 126 ++++++--------------
> 7 files changed, 119 insertions(+), 436 deletions(-)
>
> diff --git a/framework/options.py b/framework/options.py
> index dc97c38..db4bf76 100644
> --- a/framework/options.py
> +++ b/framework/options.py
> @@ -28,9 +28,7 @@ is that while you can mutate
> from __future__ import (
> absolute_import, division, print_function, unicode_literals
> )
> -import collections
> import os
> -import re
>
> import six
>
> @@ -39,129 +37,6 @@ __all__ = ['OPTIONS']
> # pylint: disable=too-few-public-methods
>
>
> -_RETYPE = type(re.compile(''))
> -
> -
> -class _ReList(collections.MutableSequence):
> - """A list-like container that only holds RegexObjects.
> -
> - This class behaves identically to a list, except that all objects are
> - forced to be RegexObjects with a flag of re.IGNORECASE (2 if one inspects
> - the object).
> -
> - If inputs do not match this object, they will be coerced to becoming such
> - an object, or they assignment will fail.
> -
> - """
> - def __init__(self, iterable=None):
> - self._wrapped = []
> - if iterable is not None:
> - self.extend(iterable)
> -
> - @staticmethod
> - def __compile(value):
> - """Ensure that the object is properly compiled.
> -
> - If the object is not a RegexObject then compile it to one, setting the
> - proper flag. If it is a RegexObject, and the flag is incorrect
> - recompile it to have the proper flags. Otherwise return it.
> -
> - """
> - if not isinstance(value, _RETYPE):
> - return re.compile(value, re.IGNORECASE)
> - elif value.flags != re.IGNORECASE:
> - return re.compile(value.pattern, re.IGNORECASE)
> - return value
> -
> - def __getitem__(self, index):
> - return self._wrapped[index]
> -
> - def __setitem__(self, index, value):
> - self._wrapped[index] = self.__compile(value)
> -
> - def __delitem__(self, index):
> - del self._wrapped[index]
> -
> - def __len__(self):
> - return len(self._wrapped)
> -
> - def insert(self, index, value):
> - self._wrapped.insert(index, self.__compile(value))
> -
> - def __eq__(self, other):
> - """Two ReList instances are the same if their wrapped list are equal."""
> - if isinstance(other, _ReList):
> - # There doesn't seem to be a better way to do this.
> - return self._wrapped == other._wrapped # pylint: disable=protected-access
> - raise TypeError('Cannot compare _ReList and non-_ReList object')
> -
> - def __ne__(self, other):
> - return not self == other
> -
> - def to_json(self):
> - """Allow easy JSON serialization.
> -
> - This returns the pattern (the string or unicode used to create the re)
> - of each re object in a list rather than the RegexObject itself. This is
> - critical for JSON serialization, and thanks to the piglit_encoder this
> - is all we need to serialize this class.
> -
> - """
> - return [l.pattern for l in self]
> -
> -
> -class _FilterReList(_ReList):
> - """A version of ReList that handles group madness.
> -
> - Groups are printed with '/' as a separator, but internally something else
> - may be used. This version replaces '/' with '.'.
> -
> - """
> - def __setitem__(self, index, value):
> - # Replace '/' with '.', this solves the problem of '/' not matching
> - # grouptools.SEPARATOR, but without needing to import grouptools
> - super(_FilterReList, self).__setitem__(index, value.replace('/', '.'))
> -
> - def insert(self, index, value):
> - super(_FilterReList, self).insert(index, value.replace('/', '.'))
> -
> -
> -class _ReListDescriptor(object):
> - """A Descriptor than ensures reassignment of _{in,ex}clude_filter is an
> - _ReList
> -
> - Without this some behavior's can get very strange. This descriptor is
> - mostly hit by testing code, but may be of use outside of testing at some
> - point.
> -
> - """
> - def __init__(self, name, type_=_ReList):
> - self.__name = name
> - self.__type = type_
> -
> - def __get__(self, instance, cls):
> - try:
> - return getattr(instance, self.__name)
> - except AttributeError as e:
> - new = _ReList()
> - try:
> - setattr(instance, self.__name, new)
> - except Exception:
> - raise e
> - return new
> -
> - def __set__(self, instance, value):
> - assert isinstance(value, (collections.Sequence, collections.Set))
> - if isinstance(value, self.__type):
> - setattr(instance, self.__name, value)
> - else:
> - setattr(instance, self.__name, self.__type(value))
> -
> - def __delete__(self, instance):
> - raise NotImplementedError('Cannot delete {} from {}'.format(
> - self.__name, instance.__class__))
> -
> -
> class _Options(object): # pylint: disable=too-many-instance-attributes
> """Contains all options for a piglit run.
>
> @@ -172,9 +47,6 @@ class _Options(object): # pylint: disable=too-many-instance-attributes
>
> Options are as follows:
> execute -- False for dry run
> - include_filter -- list of compiled regex which include exclusively tests
> - that match
> - exclude_filter -- list of compiled regex which exclude tests that match
> valgrind -- True if valgrind is to be used
> dmesg -- True if dmesg checking is desired. This forces concurrency off
> monitored -- True if monitoring is desired. This forces concurrency off
> @@ -182,13 +54,8 @@ class _Options(object): # pylint: disable=too-many-instance-attributes
> deqp_mustpass -- True to enable the use of the deqp mustpass list feature.
> """
>
> - include_filter = _ReListDescriptor('_include_filter', type_=_FilterReList)
> - exclude_filter = _ReListDescriptor('_exclude_filter', type_=_FilterReList)
> -
> def __init__(self):
> self.execute = True
> - self._include_filter = _ReList()
> - self._exclude_filter = _ReList()
> self.valgrind = False
> self.dmesg = False
> self.monitored = False
> @@ -216,9 +83,5 @@ class _Options(object): # pylint: disable=too-many-instance-attributes
> if not key.startswith('_'):
> yield key, values
>
> - # Handle the attributes that have a descriptor separately
> - yield 'include_filter', self.include_filter
> - yield 'exclude_filter', self.exclude_filter
> -
>
> OPTIONS = _Options()
> diff --git a/framework/profile.py b/framework/profile.py
> index e00fbc4..17d17db 100644
> --- a/framework/profile.py
> +++ b/framework/profile.py
> @@ -37,21 +37,59 @@ import itertools
> import multiprocessing
> import multiprocessing.dummy
> import os
> +import re
>
> import six
>
> -from framework import grouptools, exceptions, options
> +from framework import grouptools, exceptions
> from framework.dmesg import get_dmesg
> from framework.log import LogManager
> from framework.monitoring import Monitoring
> from framework.test.base import Test
>
> __all__ = [
> + 'RegexFilter',
> 'TestProfile',
> 'load_test_profile',
> ]
>
>
> +class RegexFilter(object):
> + """An object to be passed to TestProfile.filter.
> +
> + This object takes a list (or list-like object) of strings which it converts
> + to re.compiled objects (so use raw strings for escape sequences), and acts
> + as a callable for filtering tests. If a test matches any of the regex then
> + it will be scheduled to run. When the inverse keyword argument is True then
> + a test that matches any regex will not be scheduled. Regardless of the
> + value of the inverse flag if filters is empty then the test will be run.
> +
> + Arguments:
> + filters -- a list of regex compiled objects.
> +
> + Keyword Arguments:
> + inverse -- Inverse the sense of the match.
> + """
> +
> + def __init__(self, filters, inverse=False):
> + self.filters = [re.compile(f) for f in filters]
> + self.inverse = inverse
> +
> + def __call__(self, name, _): # pylint: disable=invalid-name
> + # This needs to match the signature (name, test), since it doesn't need
> + # the test instance use _.
> +
> + # If self.filters is empty then return True, we don't want to remove
> + # any tests from the run.
> + if not self.filters:
> + return True
> +
> + if not self.inverse:
> + return any(r.search(name) for r in self.filters)
> + else:
> + return not any(r.search(name) for r in self.filters)
> +
> +
> class TestDict(collections.MutableMapping):
> """A special kind of dict for tests.
>
> @@ -252,22 +290,10 @@ class TestProfile(object):
> runs it's own filters plus the filters in the self.filters name
>
> """
> - def matches_any_regexp(x, re_list):
> - return any(r.search(x) for r in re_list)
> -
> - # The extra argument is needed to match check_all's API
> - def test_matches(path, test):
> - """Filter for user-specified restrictions"""
> - return ((not options.OPTIONS.include_filter or
> - matches_any_regexp(path, options.OPTIONS.include_filter))
> - and not matches_any_regexp(path, options.OPTIONS.exclude_filter))
> -
> - filters = self.filters + [test_matches]
> -
> def check_all(item):
> """ Checks group and test name against all filters """
> path, test = item
> - for f in filters:
> + for f in self.filters:
> if not f(path, test):
> return False
> return True
> diff --git a/framework/programs/print_commands.py b/framework/programs/print_commands.py
> index 6e68eb5..5811cd2 100644
> --- a/framework/programs/print_commands.py
> +++ b/framework/programs/print_commands.py
> @@ -86,15 +86,17 @@ def main(input_):
> help="Path to results folder")
> args = parser.parse_args(input_)
>
> - options.OPTIONS.exclude_filter = args.exclude_tests
> - options.OPTIONS.include_filter = args.include_tests
> + profile_ = profile.load_test_profile(args.testProfile)
> +
> + if args.exclude_tests:
> + profile_.filters.append(profile.RegexFilter(args.exclude_tests))
> + if args.include_tests:
> + profile_.filters.append(profile.RegexFilter(args.include_tests))
>
> # Change to the piglit's path
> piglit_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
> os.chdir(piglit_dir)
>
> - profile_ = profile.load_test_profile(args.testProfile)
> -
> profile_.prepare_test_list()
> for name, test in six.iteritems(profile_.test_list):
> assert isinstance(test, Test)
> diff --git a/framework/programs/run.py b/framework/programs/run.py
> index 20a036e..2ef3b4e 100644
> --- a/framework/programs/run.py
> +++ b/framework/programs/run.py
> @@ -23,12 +23,13 @@ from __future__ import (
> absolute_import, division, print_function, unicode_literals
> )
> import argparse
> -import sys
> +import ctypes
> import os
> import os.path as path
> -import time
> -import ctypes
> +import re
> import shutil
> +import sys
> +import time
>
> import six
>
> @@ -223,6 +224,8 @@ def _create_metadata(args, name):
> opts['profile'] = args.test_profile
> opts['log_level'] = args.log_level
> opts['concurrent'] = args.concurrency
> + opts['include_filter'] = args.include_tests
> + opts['exclude_filter'] = args.exclude_tests
> if args.platform:
> opts['platform'] = args.platform
>
> @@ -277,8 +280,6 @@ def run(input_):
> args.concurrency = "none"
>
> # Pass arguments into Options
> - options.OPTIONS.exclude_filter = args.exclude_tests
> - options.OPTIONS.include_filter = args.include_tests
> options.OPTIONS.execute = args.execute
> options.OPTIONS.valgrind = args.valgrind
> options.OPTIONS.dmesg = args.dmesg
> @@ -335,6 +336,13 @@ def run(input_):
> for p in profiles:
> p.monitoring = args.monitored
>
> + for p in profiles:
> + if args.exclude_tests:
> + p.filters.append(profile.RegexFilter(args.exclude_tests,
> + inverse=True))
> + if args.include_tests:
> + p.filters.append(profile.RegexFilter(args.include_tests))
> +
> time_elapsed = TimeAttribute(start=time.time())
>
> profile.run(profiles, args.log_level, backend, args.concurrency)
> @@ -366,8 +374,6 @@ def resume(input_):
> _disable_windows_exception_messages()
>
> results = backends.load(args.results_path)
> - options.OPTIONS.exclude_filter = results.options['exclude_filter']
> - options.OPTIONS.include_filter = results.options['include_filter']
> options.OPTIONS.execute = results.options['execute']
> options.OPTIONS.valgrind = results.options['valgrind']
> options.OPTIONS.dmesg = results.options['dmesg']
> @@ -407,7 +413,15 @@ def resume(input_):
> if options.OPTIONS.monitored:
> p.monitoring = options.OPTIONS.monitored
>
> - p.filters.append(lambda n, _: n not in exclude_tests)
> + if exclude_tests:
> + p.filters.append(lambda n, _: n not in exclude_tests)
> + if results.options['exclude_filter']:
> + p.filters.append(
> + profile.RegexFilter(results.options['exclude_filter'],
> + inverse=True))
> + if results.options['include_filter']:
> + p.filters.append(
> + profile.RegexFilter(results.options['include_filter']))
>
> # This is resumed, don't bother with time since it won't be accurate anyway
> profile.run(
> diff --git a/framework/summary/feature.py b/framework/summary/feature.py
> index a66a49b..7d426e7 100644
> --- a/framework/summary/feature.py
> +++ b/framework/summary/feature.py
> @@ -1,4 +1,4 @@
> -# Copyright (c) 2015-2016 Intel Corporation
> +# Copyright (c) 2016-2016 Intel Corporation
>
> # Permission is hereby granted, free of charge, to any person
> # obtaining a copy of this software and associated documentation
> @@ -30,7 +30,7 @@ try:
> except ImportError:
> import json
>
> -from framework import options, exceptions, profile, status
> +from framework import exceptions, profile, status
>
>
> class FeatResults(object): # pylint: disable=too-few-public-methods
> @@ -57,16 +57,18 @@ class FeatResults(object): # pylint: disable=too-few-public-methods
> for feature in feature_data:
> self.features.add(feature)
>
> + profiles[feature] = profile_orig.copy()
> +
> incl_str = feature_data[feature]["include_tests"]
> excl_str = feature_data[feature]["exclude_tests"]
>
> - include_filter = [incl_str] if incl_str and not incl_str.isspace() else []
> - exclude_filter = [excl_str] if excl_str and not excl_str.isspace() else []
> -
> - options.OPTIONS.exclude_filter = exclude_filter
> - options.OPTIONS.include_filter = include_filter
> -
> - profiles[feature] = profile_orig.copy()
> + profiles[feature].filters.append(
> + profile.RegexFilter(
> + [incl_str] if incl_str and not incl_str.isspace() else []))
> + profiles[feature].filters.append(
> + profile.RegexFilter(
> + [excl_str] if excl_str and not excl_str.isspace() else [],
> + inverse=True))
>
> # An empty list will raise PiglitFatalError exception
> # But for reporting we need to handle this situation
> diff --git a/unittests/framework/test_options.py b/unittests/framework/test_options.py
> index 65ff946..bf296c1 100644
> --- a/unittests/framework/test_options.py
> +++ b/unittests/framework/test_options.py
> @@ -23,9 +23,6 @@
> from __future__ import (
> absolute_import, division, print_function, unicode_literals
> )
> -import re
> -
> -import pytest
>
> from framework import options
>
> @@ -33,180 +30,6 @@ from framework import options
> # pylint: disable=invalid-name
> # pylint: disable=no-self-use
>
> -_RETYPE = type(re.compile(''))
> -
> -
> -def test_ReList_iterable_argument():
> - """options._ReList: handles an iterable argument correctly"""
> - test = options._ReList(['foo'])
> - assert isinstance(test[0], _RETYPE)
> -
> -
> -class TestReList(object):
> - """Tests for the ReList class.
> -
> - These particular tests don't mutate the state of ReList, and thus can be
> - run with the same instance over and over, other tests that do mutate the
> - state need a per test ReList instance.
> -
> - """
> - @classmethod
> - def setup_class(cls):
> - cls.test = options._ReList(['foo'])
> -
> - def test_eq(self):
> - """Test options._ReList.__eq__."""
> - test1 = ['foo']
> - test2 = options._ReList(['foo'])
> -
> - with pytest.raises(TypeError):
> - assert self.test == test1
> -
> - assert self.test == test2
> -
> - def test_ne(self):
> - """Test hoptions._ReList.__ne__."""
> - test1 = ['bar']
> - test2 = options._ReList(['bar'])
> -
> - with pytest.raises(TypeError):
> - assert self.test != test1
> -
> - assert self.test != test2
> -
> - def test_getitem(self):
> - """options._ReList.__getitem__: returns expected value."""
> - assert isinstance(self.test[0], _RETYPE)
> -
> - def test_flags(self):
> - """options._ReList.__getitem__: sets flags correctly."""
> - assert self.test[0].flags & re.IGNORECASE != 0
> -
> - def test_len(self):
> - """options._ReList.len: returns expected values."""
> - assert len(self.test) == 1
> -
> - def test_to_json(self):
> - """options._ReList.to_json: returns expected values."""
> - assert self.test.to_json() == ['foo']
> -
> -
> -class TestReListMutate(object):
> - """Tests for ReList that mutate state."""
> - test = None
> -
> - def setup(self):
> - self.test = options._ReList(['foo'])
> -
> - def test_relist_insert(self):
> - """options._ReList.len: inserts value as expected"""
> - obj = re.compile('bar', re.IGNORECASE)
> -
> - self.test.insert(0, obj)
> -
> - assert self.test[0] == obj
> -
> - def test_relist_delitem(self):
> - """options._ReList.len: removes value as expected"""
> - del self.test[0]
> -
> - assert len(self.test) == 0
> -
> - def test_relist_setitem(self):
> - """options._ReList.__setitem__: replaces values"""
> - sentinel = re.compile('bar')
> - self.test[0] = sentinel
> -
> - # The pattern must be tested because the flags on the re object might
> - # require it to be recompiled, thus they might not be the same object,
> - # or even be equal according to python (though they are for the
> - # purposes of this test)
> - assert self.test[0].pattern == sentinel.pattern
> -
> -
> -class TestReListDescriptor(object):
> - """Test the ReListDescriptor class.
> -
> - Since this class is a descriptor it needs to be attached to an object at
> - the class level.
> -
> - """
> - test = None
> -
> - @classmethod
> - def setup_class(cls):
> - """Create a test object."""
> - class _Test(object):
> - desc = options._ReListDescriptor('test_desc')
> - notexists = options._ReListDescriptor('test_notexists')
> -
> - def __init__(self):
> - self.test_desc = options._ReList()
> -
> - cls._test = _Test
> -
> - def setup(self):
> - self.test = self._test()
> -
> - def test_get_exists(self):
> - """options._ReListDescriptor.__get__: Returns value if it exists."""
> - assert self.test.desc == self.test.test_desc
> -
> - def test_get_not_exists(self):
> - """options._ReListDescriptor.__get__: Returns new _ReList if it doesn't
> - exists."""
> - assert self.test.notexists == self.test.test_notexists # pylint: disable=no-member
> -
> - def test_get_not_exists_fail(self, mocker):
> - """options._ReListDescriptor.__get__: Raises AttributError if name
> - doesn't exist and can't be created."""
> - mocker.patch('framework.options.setattr',
> - mocker.Mock(side_effect=Exception),
> - create=True)
> -
> - with pytest.raises(AttributeError):
> - self.test.notexists # pylint: disable=pointless-statement
> -
> - def test_set_relist(self):
> - """options._ReListDescriptor.__set__: assigns an ReList without
> - copying."""
> - val = options._ReList(['foo'])
> - self.test.desc = val
> - assert self.test.desc is val
> -
> - def test_set_other(self):
> - """options._ReListDescriptor.__set__: converts other types to ReList"""
> - val = options._ReList(['foo'])
> - self.test.desc = ['foo']
> - assert self.test.desc == val
> -
> - def test_delete(self):
> - """options._ReListDescriptor.__delete___: raises NotImplementedError"""
> - with pytest.raises(NotImplementedError):
> - del self.test.desc
> -
> -
> -class TestFilterReList(object):
> - """Tests for FilterReList.
> -
> - provides a unique instance per test, which protects against state mutation.
> -
> - """
> - test = None
> -
> - def setup(self):
> - self.test = options._FilterReList(['foo'])
> -
> - def test_setitem(self):
> - """options._FilterReList.__setitem__: replaces '/' with '.'."""
> - self.test[0] = 'foo/bar'
> - assert self.test[0].pattern == 'foo.bar'
> -
> - def test_filterrelist_insert(self):
> - """options._FilterReList.insert: replaces '/' with '.'."""
> - self.test.insert(0, 'foo/bar')
> - assert self.test[0].pattern == 'foo.bar'
> -
>
> def test_options_clear():
> """options.Options.clear(): resests options values to init state."""
> @@ -215,7 +38,6 @@ def test_options_clear():
> test = options._Options()
> test.execute = False
> test.sync = True
> - test.exclude_filter.append('foo')
> test.clear()
>
> assert list(iter(baseline)) == list(iter(test))
> diff --git a/unittests/framework/test_profile.py b/unittests/framework/test_profile.py
> index f2aa5b5..ea4ee70 100644
> --- a/unittests/framework/test_profile.py
> +++ b/unittests/framework/test_profile.py
> @@ -23,11 +23,6 @@
> from __future__ import (
> absolute_import, division, print_function, unicode_literals
> )
> -import copy
> -try:
> - from unittest import mock
> -except ImportError:
> - import mock
>
> import pytest
> import six
> @@ -35,7 +30,6 @@ import six
> from framework import dmesg
> from framework import exceptions
> from framework import grouptools
> -from framework import options
> from framework import profile
> from framework.test.gleantest import GleanTest
> from . import utils
> @@ -101,86 +95,6 @@ class TestTestProfile(object):
> profile_.dmesg = False
> assert isinstance(profile_.dmesg, dmesg.DummyDmesg)
>
> - class TestPrepareTestList(object):
> - """Create tests for TestProfile.prepare_test_list filtering."""
> -
> - @classmethod
> - def setup_class(cls):
> - cls.opts = None
> - cls.data = None
> - cls.__patcher = mock.patch('framework.profile.options.OPTIONS',
> - new_callable=options._Options)
> -
> - def setup(self):
> - """Setup each test."""
> - self.data = profile.TestDict()
> - self.data[grouptools.join('group1', 'test1')] = \
> - utils.Test(['thingy'])
> - self.data[grouptools.join('group1', 'group3', 'test2')] = \
> - utils.Test(['thing'])
> - self.data[grouptools.join('group3', 'test5')] = \
> - utils.Test(['other'])
> - self.data[grouptools.join('group4', 'Test9')] = \
> - utils.Test(['is_caps'])
> - self.opts = self.__patcher.start()
> -
> - def teardown(self):
> - self.__patcher.stop()
> -
> - def test_matches_filter_mar_1(self):
> - """profile.TestProfile.prepare_test_list: 'not env.filter or
> - matches_any_regex()' env.filter is False.
> -
> - Nothing should be filtered.
> - """
> - profile_ = profile.TestProfile()
> - profile_.test_list = self.data
> - profile_.prepare_test_list()
> -
> - assert dict(profile_.test_list) == dict(self.data)
> -
> - def test_matches_filter_mar_2(self):
> - """profile.TestProfile.prepare_test_list: 'not env.filter or
> - matches_any_regex()' mar is False.
> - """
> - self.opts.include_filter = ['test5']
> -
> - profile_ = profile.TestProfile()
> - profile_.test_list = self.data
> - profile_.prepare_test_list()
> -
> - baseline = {
> - grouptools.join('group3', 'test5'): utils.Test(['other'])}
> -
> - assert dict(profile_.test_list) == baseline
> -
> - def test_matches_exclude_mar(self):
> - """profile.TestProfile.prepare_test_list: 'not
> - matches_any_regexp()'.
> - """
> - self.opts.exclude_filter = ['test5']
> -
> - baseline = copy.deepcopy(self.data)
> - del baseline[grouptools.join('group3', 'test5')]
> -
> - profile_ = profile.TestProfile()
> - profile_.test_list = self.data
> - profile_.prepare_test_list()
> -
> - assert dict(profile_.test_list) == dict(baseline)
> -
> - def test_matches_include_caps(self):
> - """profile.TestProfile.prepare_test_list: matches capitalized
> - tests.
> - """
> - self.opts.exclude_filter = ['test9']
> -
> - profile_ = profile.TestProfile()
> - profile_.test_list = self.data
> - profile_.prepare_test_list()
> -
> - assert grouptools.join('group4', 'Test9') not in profile_.test_list
> -
> class TestGroupManager(object):
> """Tests for TestProfile.group_manager."""
>
> @@ -386,3 +300,43 @@ class TestTestDict(object):
> test['a'] = utils.Test(['bar'])
>
> assert test['a'].command == ['bar']
> +
> +
> +class TestRegexFilter(object):
> + """Tests for the RegexFilter class."""
> +
> + class TestNormal(object):
> + """Tests for inverse set to False (default)."""
> +
> + def test_empty(self):
> + """Returns True when no filters are provided."""
> + test = profile.RegexFilter([])
> + assert test('foobob', None)
> +
> + def test_matches(self):
> + """Returns True when the test matches any regex."""
> + test = profile.RegexFilter([r'foo', r'bar'])
> + assert test('foobob', None)
> +
> + def test_not_matches(self):
> + """Returns True when the test matches any regex."""
> + test = profile.RegexFilter([r'fob', r'bar'])
> + assert not test('foobob', None)
> +
> + class TestInverse(object):
> + """Tests for inverse set to True."""
> +
> + def test_empty(self):
> + """Returns True when no filters are provided."""
> + test = profile.RegexFilter([], inverse=True)
> + assert test('foobob', None)
> +
> + def test_matches(self):
> + """Returns False when the test matches any regex."""
> + test = profile.RegexFilter([r'foo', r'bar'], inverse=True)
> + assert not test('foobob', None)
> +
> + def test_not_matches(self):
> + """Returns False when the test matches any regex."""
> + test = profile.RegexFilter([r'fob', r'bar'], inverse=True)
> + assert test('foobob', None)
More information about the Piglit
mailing list