[Piglit] [PATCH v4 16/27] framework: Pull {include, exclude}_filter out of Options
Dylan Baker
dylan at pnwbakers.com
Wed Nov 16 19:46:07 UTC 2016
Quoting Alejandro PiƱeiro (2016-11-16 00:17:55)
> 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
I feel really, silly. The bug is actually pretty simple to fix. Before this
patch we compiled the regular expressions using re.IGNORECASE, which isn't in
the new implementation. I'll send a patch and CC you on it.
Dylan
>
> > ---
> > 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)
>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 455 bytes
Desc: signature
URL: <https://lists.freedesktop.org/archives/piglit/attachments/20161116/28f17223/attachment-0001.sig>
More information about the Piglit
mailing list