Title: [91785] trunk/Tools
Revision
91785
Author
[email protected]
Date
2011-07-26 14:42:29 -0700 (Tue, 26 Jul 2011)

Log Message

Introduce a way to convert between specifier lists and TestConfiguration sets.
https://bugs.webkit.org/show_bug.cgi?id=65094

Add TestConfigurationConverter, a facility to convert:
1) a set of specifiers into a set of TestConfiguration instances;
2) a set of TestConfiguration instances into a list of sets of specifiers.

Reviewed by Adam Barth.

* Scripts/webkitpy/layout_tests/models/test_configuration.py: Added TestConfigurationConverter.
* Scripts/webkitpy/layout_tests/models/test_configuration_unittest.py: Added tests for it.

Modified Paths

Diff

Modified: trunk/Tools/ChangeLog (91784 => 91785)


--- trunk/Tools/ChangeLog	2011-07-26 21:37:22 UTC (rev 91784)
+++ trunk/Tools/ChangeLog	2011-07-26 21:42:29 UTC (rev 91785)
@@ -1,3 +1,17 @@
+2011-07-26  Dimitri Glazkov  <[email protected]>
+
+        Introduce a way to convert between specifier lists and TestConfiguration sets.
+        https://bugs.webkit.org/show_bug.cgi?id=65094
+
+        Add TestConfigurationConverter, a facility to convert:
+        1) a set of specifiers into a set of TestConfiguration instances;
+        2) a set of TestConfiguration instances into a list of sets of specifiers.
+
+        Reviewed by Adam Barth.
+
+        * Scripts/webkitpy/layout_tests/models/test_configuration.py: Added TestConfigurationConverter.
+        * Scripts/webkitpy/layout_tests/models/test_configuration_unittest.py: Added tests for it.
+
 2011-07-26  Alexandru Chiculita  <[email protected]>
 
         CSS Regions build bot should build with "--css-regions" and "--css-exclusion" flags

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/models/test_configuration.py (91784 => 91785)


--- trunk/Tools/Scripts/webkitpy/layout_tests/models/test_configuration.py	2011-07-26 21:37:22 UTC (rev 91784)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/models/test_configuration.py	2011-07-26 21:42:29 UTC (rev 91785)
@@ -35,6 +35,11 @@
         self.build_type = build_type or port.options.configuration.lower()
         self.graphics_type = graphics_type or port.graphics_type()
 
+    @classmethod
+    def category_order(cls):
+        """The most common human-readable order in which the configuration properties are listed."""
+        return ['version', 'architecture', 'build_type', 'graphics_type']
+
     def items(self):
         return self.__dict__.items()
 
@@ -87,3 +92,148 @@
 
     def all_graphics_types(self):
         return ('cpu', 'gpu')
+
+
+class TestConfigurationConverter:
+    def __init__(self, all_test_configurations, configuration_macros=None):
+        self._all_test_configurations = all_test_configurations
+        self._configuration_macros = configuration_macros or {}
+        self._specifier_to_configuration_set = {}
+        self._specifier_to_category = {}
+        self._collapsing_sets_by_size = {}
+        self._junk_specifier_combinations = {}
+        collapsing_sets_by_category = {}
+        matching_sets_by_category = {}
+        for configuration in all_test_configurations:
+            for category, specifier in configuration.items():
+                self._specifier_to_configuration_set.setdefault(specifier, set()).add(configuration)
+                self._specifier_to_category[specifier] = category
+                collapsing_sets_by_category.setdefault(category, set()).add(specifier)
+                # FIXME: This seems extra-awful.
+                for cat2, spec2 in configuration.items():
+                    if category == cat2:
+                        continue
+                    matching_sets_by_category.setdefault(specifier, {}).setdefault(cat2, set()).add(spec2)
+        for collapsing_set in collapsing_sets_by_category.values():
+            self._collapsing_sets_by_size.setdefault(len(collapsing_set), set()).add(frozenset(collapsing_set))
+
+        def category_priority(category):
+            return TestConfiguration.category_order().index(category)
+
+        def specifier_priority(specifier):
+            return category_priority(self._specifier_to_category[specifier])
+
+        for specifier, sets_by_category in matching_sets_by_category.items():
+            for category, set_by_category in sets_by_category.items():
+                if len(set_by_category) == 1 and category_priority(category) > specifier_priority(specifier):
+                    self._junk_specifier_combinations[specifier] = set_by_category
+
+    def to_config_set(self, specifier_set):
+        """Convert a list of specifiers into a set of TestConfiguration instances."""
+        if len(specifier_set) == 0:
+            return self._all_test_configurations
+
+        matching_sets = {}
+
+        def update_matching_set(specifier):
+            configurations = self._specifier_to_configuration_set[specifier]
+            category = self._specifier_to_category[specifier]
+            matching_sets.setdefault(category, set()).update(configurations)
+
+        for specifier in specifier_set:
+            expanded_specifiers = self._configuration_macros.get(specifier)
+            if expanded_specifiers:
+                for expanded_specifier in expanded_specifiers:
+                    update_matching_set(expanded_specifier)
+            else:
+                update_matching_set(specifier)
+
+        return set.intersection(*matching_sets.values())
+
+    def to_specifiers_list(self, test_configuration_set):
+        """Convert a set of TestConfiguration instances into one or more list of specifiers."""
+
+        # Easy out: if the set is all configurations, the modifier is empty.
+        if len(test_configuration_set) == len(self._all_test_configurations):
+            return []
+
+        # 1) Build a list of specifier sets, discarding specifiers that don't add value.
+        specifiers_list = []
+        for config in test_configuration_set:
+            values = set(config.values())
+            for specifier, junk_specifier_set in self._junk_specifier_combinations.items():
+                if specifier in values:
+                    values -= junk_specifier_set
+            specifiers_list.append(frozenset(values))
+
+        # FIXME: Replace with iteritools.combinations when we obsolete Python 2.5.
+        def combinations(iterable, r):
+            """This function is borrowed verbatim from http://docs.python.org/library/itertools.html#itertools.combinations."""
+            pool = tuple(iterable)
+            n = len(pool)
+            if r > n:
+                return
+            indices = range(r)
+            yield tuple(pool[i] for i in indices)
+            while True:
+                for i in reversed(range(r)):
+                    if indices[i] != i + n - r:
+                        break
+                else:
+                    return
+                indices[i] += 1
+                for j in range(i + 1, r):
+                    indices[j] = indices[j - 1] + 1
+                yield tuple(pool[i] for i in indices)
+
+        def intersect_combination(combination):
+            return set.intersection(*[set(specifiers) for specifiers in combination])
+
+        def symmetric_difference(iterable):
+            return reduce(lambda x, y: x ^ y, iterable)
+
+        def try_collapsing(size, collapsing_sets):
+            if len(specifiers_list) < size:
+                return False
+            for combination in combinations(specifiers_list, size):
+                if symmetric_difference(combination) in collapsing_sets:
+                    for item in combination:
+                        specifiers_list.remove(item)
+                    specifiers_list.append(frozenset(intersect_combination(combination)))
+                    return True
+            return False
+
+        # 2) Collapse specifier sets with common specifiers:
+        #   (xp, release, gpu), (xp, release, cpu) --> (xp, x86, release)
+        for size, collapsing_sets in self._collapsing_sets_by_size.items():
+            while try_collapsing(size, collapsing_sets):
+                pass
+
+        def try_abbreviating():
+            if len(specifiers_list) < 2:
+                return False
+            for combination in combinations(specifiers_list, 2):
+                for collapsing_set in collapsing_sets:
+                    diff = symmetric_difference(combination)
+                    if diff <= collapsing_set:
+                        common = intersect_combination(combination)
+                        for item in combination:
+                            specifiers_list.remove(item)
+                        specifiers_list.append(frozenset(common | diff))
+                        return True
+            return False
+
+        # 3) Abbreviate specifier sets by combining specifiers across categories.
+        #   (xp, release), (win7, release) --> (xp, win7, release)
+        while try_abbreviating():
+            pass
+
+        # 4) Substitute specifier subsets that match macros witin each set:
+        #   (xp, vista, win7, release) -> (win, release)
+        for i in range(len(specifiers_list)):
+            for macro_specifier, macro in self._configuration_macros.items():
+                diff = set(specifiers_list[i]) - set(macro)
+                if specifiers_list[i] != diff:
+                    specifiers_list[i] = frozenset(diff | set([macro_specifier]))
+
+        return specifiers_list

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/models/test_configuration_unittest.py (91784 => 91785)


--- trunk/Tools/Scripts/webkitpy/layout_tests/models/test_configuration_unittest.py	2011-07-26 21:37:22 UTC (rev 91784)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/models/test_configuration_unittest.py	2011-07-26 21:42:29 UTC (rev 91785)
@@ -94,3 +94,192 @@
         all_configs = TestConfiguration(None, 'xp', 'x86', 'release', 'cpu').all_test_configurations()
         for config in all_configs:
             self.assertTrue(isinstance(config, TestConfiguration))
+
+
+class TestConfigurationConverterTest(unittest.TestCase):
+    def __init__(self, testFunc):
+        self._all_test_configurations = set()
+        for version, architecture in (('snowleopard', 'x86'), ('xp', 'x86'), ('win7', 'x86'), ('lucid', 'x86'), ('lucid', 'x86_64')):
+            for build_type in ('debug', 'release'):
+                for graphics_type in ('cpu', 'gpu'):
+                    self._all_test_configurations.add(TestConfiguration(None, version, architecture, build_type, graphics_type))
+        self._macros = {
+            'mac': ['snowleopard'],
+            'win': ['xp', 'win7'],
+            'linux': ['lucid'],
+        }
+        unittest.TestCase.__init__(self, testFunc)
+
+    def test_to_config_set(self):
+        converter = TestConfigurationConverter(self._all_test_configurations)
+
+        self.assertEquals(converter.to_config_set(set()), self._all_test_configurations)
+
+        configs_to_match = set([
+            TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'xp', 'x86', 'release', 'cpu'),
+        ])
+        self.assertEquals(converter.to_config_set(set(['xp', 'release'])), configs_to_match)
+
+        configs_to_match = set([
+            TestConfiguration(None, 'snowleopard', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'win7', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86_64', 'release', 'gpu'),
+       ])
+        self.assertEquals(converter.to_config_set(set(['gpu', 'release'])), configs_to_match)
+
+        configs_to_match = set([
+             TestConfiguration(None, 'lucid', 'x86_64', 'release', 'gpu'),
+             TestConfiguration(None, 'lucid', 'x86_64', 'debug', 'gpu'),
+             TestConfiguration(None, 'lucid', 'x86_64', 'release', 'cpu'),
+             TestConfiguration(None, 'lucid', 'x86_64', 'debug', 'cpu'),
+        ])
+        self.assertEquals(converter.to_config_set(set(['x86_64'])), configs_to_match)
+
+        configs_to_match = set([
+            TestConfiguration(None, 'lucid', 'x86_64', 'release', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86_64', 'debug', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86_64', 'release', 'cpu'),
+            TestConfiguration(None, 'lucid', 'x86_64', 'debug', 'cpu'),
+            TestConfiguration(None, 'lucid', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86', 'debug', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86', 'release', 'cpu'),
+            TestConfiguration(None, 'lucid', 'x86', 'debug', 'cpu'),
+            TestConfiguration(None, 'snowleopard', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'snowleopard', 'x86', 'debug', 'gpu'),
+            TestConfiguration(None, 'snowleopard', 'x86', 'release', 'cpu'),
+            TestConfiguration(None, 'snowleopard', 'x86', 'debug', 'cpu'),
+        ])
+        self.assertEquals(converter.to_config_set(set(['lucid', 'snowleopard'])), configs_to_match)
+
+        configs_to_match = set([
+            TestConfiguration(None, 'lucid', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86', 'debug', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86', 'release', 'cpu'),
+            TestConfiguration(None, 'lucid', 'x86', 'debug', 'cpu'),
+            TestConfiguration(None, 'snowleopard', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'snowleopard', 'x86', 'debug', 'gpu'),
+            TestConfiguration(None, 'snowleopard', 'x86', 'release', 'cpu'),
+            TestConfiguration(None, 'snowleopard', 'x86', 'debug', 'cpu'),
+        ])
+        self.assertEquals(converter.to_config_set(set(['lucid', 'snowleopard', 'x86'])), configs_to_match)
+
+        configs_to_match = set([
+            TestConfiguration(None, 'lucid', 'x86_64', 'release', 'cpu'),
+            TestConfiguration(None, 'lucid', 'x86', 'release', 'cpu'),
+            TestConfiguration(None, 'snowleopard', 'x86', 'release', 'cpu'),
+        ])
+        self.assertEquals(converter.to_config_set(set(['lucid', 'snowleopard', 'release', 'cpu'])), configs_to_match)
+
+    def test_macro_expansion(self):
+        converter = TestConfigurationConverter(self._all_test_configurations, self._macros)
+
+        configs_to_match = set([
+            TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'xp', 'x86', 'release', 'cpu'),
+            TestConfiguration(None, 'win7', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'win7', 'x86', 'release', 'cpu'),
+        ])
+        self.assertEquals(converter.to_config_set(set(['win', 'release'])), configs_to_match)
+
+        configs_to_match = set([
+            TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'win7', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86_64', 'release', 'gpu'),
+        ])
+        self.assertEquals(converter.to_config_set(set(['win', 'lucid', 'release', 'gpu'])), configs_to_match)
+
+        configs_to_match = set([
+            TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'win7', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'snowleopard', 'x86', 'release', 'gpu'),
+        ])
+        self.assertEquals(converter.to_config_set(set(['win', 'mac', 'release', 'gpu'])), configs_to_match)
+
+    def test_to_specifier_lists(self):
+        converter = TestConfigurationConverter(self._all_test_configurations)
+
+        self.assertEquals(converter.to_specifiers_list(set(self._all_test_configurations)), [])
+
+        configs_to_match = set([
+            TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'xp', 'x86', 'release', 'cpu'),
+        ])
+        self.assertEquals(converter.to_specifiers_list(configs_to_match), [set(['release', 'xp'])])
+
+        configs_to_match = set([
+            TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'xp', 'x86', 'release', 'cpu'),
+            TestConfiguration(None, 'xp', 'x86', 'debug', 'gpu'),
+            TestConfiguration(None, 'xp', 'x86', 'debug', 'cpu'),
+        ])
+        self.assertEquals(converter.to_specifiers_list(configs_to_match), [set(['xp'])])
+
+        configs_to_match = set([
+            TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86_64', 'debug', 'cpu'),
+        ])
+        self.assertEquals(converter.to_specifiers_list(configs_to_match), [set(['debug', 'x86_64', 'lucid', 'cpu']), set(['release', 'gpu', 'xp'])])
+
+        configs_to_match = set([
+            TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'xp', 'x86', 'release', 'cpu'),
+            TestConfiguration(None, 'lucid', 'x86_64', 'debug', 'cpu'),
+            TestConfiguration(None, 'lucid', 'x86', 'debug', 'cpu'),
+            TestConfiguration(None, 'lucid', 'x86_64', 'debug', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86', 'debug', 'gpu'),
+        ])
+        self.assertEquals(converter.to_specifiers_list(configs_to_match), [set(['release', 'xp']), set(['debug', 'lucid'])])
+
+        configs_to_match = set([
+            TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'snowleopard', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'win7', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86_64', 'release', 'gpu'),
+        ])
+        self.assertEquals(converter.to_specifiers_list(configs_to_match), [set(['release', 'gpu'])])
+
+        configs_to_match = set([
+            TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'snowleopard', 'x86', 'release', 'gpu'),
+        ])
+        self.assertEquals(converter.to_specifiers_list(configs_to_match), [set(['xp', 'snowleopard', 'release', 'gpu'])])
+
+        configs_to_match = set([
+            TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'snowleopard', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'win7', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'win7', 'x86', 'debug', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86', 'release', 'gpu'),
+        ])
+        self.assertEquals(converter.to_specifiers_list(configs_to_match), [set(['release', 'gpu', 'lucid', 'x86']), set(['gpu', 'win7']), set(['release', 'gpu', 'xp', 'snowleopard'])])
+
+    def test_macro_collapsing(self):
+        converter = TestConfigurationConverter(self._all_test_configurations, self._macros)
+
+        configs_to_match = set([
+            TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'xp', 'x86', 'release', 'cpu'),
+            TestConfiguration(None, 'win7', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'win7', 'x86', 'release', 'cpu'),
+        ])
+        self.assertEquals(converter.to_specifiers_list(configs_to_match), [set(['win', 'release'])])
+
+        configs_to_match = set([
+            TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'win7', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'lucid', 'x86_64', 'release', 'gpu'),
+        ])
+        self.assertEquals(converter.to_specifiers_list(configs_to_match), [set(['win', 'linux', 'release', 'gpu'])])
+
+        configs_to_match = set([
+            TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'win7', 'x86', 'release', 'gpu'),
+            TestConfiguration(None, 'snowleopard', 'x86', 'release', 'gpu'),
+        ])
+        self.assertEquals(converter.to_specifiers_list(configs_to_match), [set(['win', 'mac', 'release', 'gpu'])])
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to