[v4,8/27] framework/profile: add a copy method to profile

Submitted by Dylan Baker on Nov. 9, 2016, 8:53 p.m.

Details

Message ID b2c859072c79c873e2639aa3c4b64bd4422d0ca9.1478724535.git-series.dylan@pnwbakers.com
State New
Headers show
Series "Series without cover letter" ( rev: 1 ) in Piglit

Not browsing as part of any series.

Commit Message

Dylan Baker Nov. 9, 2016, 8:53 p.m.
This will allow a profile to be copied and "subclassed" without
affecting the original profile. This will allow a long-standing bug that
made it impossible to run two subclasses of all.py (say shader.py and
glslparser.py) at the same time, since they would both try to modify the
all.py profile in incompatible ways.

Signed-off-by: Dylan Baker <dylanx.c.baker@intel.com>
---
 framework/profile.py                 | 16 +++++++++-
 framework/programs/print_commands.py |  2 +-
 unittests/framework/test_profile.py  | 52 +++++++++++++++++++++++++++++-
 3 files changed, 69 insertions(+), 1 deletion(-)

Patch hide | download patch | download mbox

diff --git a/framework/profile.py b/framework/profile.py
index 4d111bf..a64855e 100644
--- a/framework/profile.py
+++ b/framework/profile.py
@@ -31,6 +31,7 @@  from __future__ import (
 )
 import collections
 import contextlib
+import copy
 import importlib
 import itertools
 import multiprocessing
@@ -398,6 +399,21 @@  class TestProfile(object):
     def teardown(self):
         """Method to od post-run teardown."""
 
+    def copy(self):
+        """Create a copy of the TestProfile.
+
+        This method creates a copy with references to the original instance
+        (using copy.copy), except for the test_list attribute, which is copied
+        using copy.deepcopy, which is necessary to ensure that filter_tests
+        only affects the right instance. This allows profiles to be
+        "subclassed" by other profiles, without modifying the original.
+        """
+        new = copy.copy(self)
+        new.test_list = copy.deepcopy(self.test_list)
+        new.forced_test_list = copy.copy(self.forced_test_list)
+        new.filters = copy.copy(self.filters)
+        return new
+
 
 def load_test_profile(filename):
     """Load a python module and return it's profile attribute.
diff --git a/framework/programs/print_commands.py b/framework/programs/print_commands.py
index 033ca87..6e68eb5 100644
--- a/framework/programs/print_commands.py
+++ b/framework/programs/print_commands.py
@@ -95,7 +95,7 @@  def main(input_):
 
     profile_ = profile.load_test_profile(args.testProfile)
 
-    profile_._prepare_test_list()
+    profile_.prepare_test_list()
     for name, test in six.iteritems(profile_.test_list):
         assert isinstance(test, Test)
         print(args.format_string.format(
diff --git a/unittests/framework/test_profile.py b/unittests/framework/test_profile.py
index 6671349..5ef95e4 100644
--- a/unittests/framework/test_profile.py
+++ b/unittests/framework/test_profile.py
@@ -285,6 +285,58 @@  class TestTestProfile(object):
 
             assert grouptools.join('foo', 'abc') in self.profile.test_list
 
+    class TestCopy(object):
+        """Tests for the copy method."""
+
+        @pytest.fixture
+        def fixture(self):
+            orig = profile.TestProfile()
+            orig.test_list['foo'] = utils.Test(['foo'])
+            orig.test_list['bar'] = utils.Test(['bar'])
+            orig.filters = [lambda name, _: name != 'bar']
+            orig.forced_test_list = ['foo']
+            return orig
+
+        def test_filters(self, fixture):
+            """The filters attribute is copied correctly."""
+            new = fixture.copy()
+
+            # Assert that the fixtures are equivalent, but not the same
+            assert fixture.filters == new.filters
+            assert fixture.filters is not new.filters
+
+            # And double check by modifying one of them and asserting that the
+            # other has not changed.
+            new.filters.append(lambda name, _: name != 'oink')
+            assert len(fixture.filters) == 1
+
+        def test_forced_test_list(self, fixture):
+            """The forced_test_list attribute is copied correctly."""
+            new = fixture.copy()
+
+            # Assert that the fixtures are equivalent, but not the same
+            assert fixture.forced_test_list == new.forced_test_list
+            assert fixture.forced_test_list is not new.forced_test_list
+
+            # And double check by modifying one of them and asserting that the
+            # other has not changed.
+            del new.forced_test_list[0]
+            assert fixture.forced_test_list[0] == 'foo'
+
+        def test_test_list(self, fixture):
+            """The test_list attribute is copied correctly."""
+            new = fixture.copy()
+
+            # Assert that the fixtures are equivalent, but not the same
+            assert fixture.test_list == new.test_list
+            assert fixture.test_list is not new.test_list
+
+        def test_prepare_test_list(self, fixture):
+            """The prepare_test_list method doesn't affect both."""
+            new = fixture.copy()
+            new.prepare_test_list()
+            assert new.test_list != fixture.test_list
+
 
 class TestTestDict(object):
     """Tests for the TestDict object."""