Title: [92147] trunk/Tools
Revision
92147
Author
dglaz...@chromium.org
Date
2011-08-01 15:22:27 -0700 (Mon, 01 Aug 2011)

Log Message

Teach TestExpectationSerializer about parsed expectations.
https://bugs.webkit.org/show_bug.cgi?id=65444

This is a bit largish in size, but the essentials are:
* TestExpectationSerializer, given a parsed TestExpectationLine, can now spit out a pretty string.
* We now store original content of the expectation line on TestExpectationLine.
* Lots of tests.

Reviewed by Adam Barth.

* Scripts/webkitpy/layout_tests/models/test_configuration.py: Fixed an issue where we didn't
    populate macros correctly, also fixed an issue where we incorrectly returned an empty list
    for all configurations.
* Scripts/webkitpy/layout_tests/models/test_configuration_unittest.py: Added tests for those.
* Scripts/webkitpy/layout_tests/models/test_expectations.py: Removed vestiges of code long gone,
    refactored TestExpectationsSerializer to recognize and correctly serialize parsed TestExpectationLine instances,
    changed to store and use TestExpectationLine.original_string.
* Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py: Added tests.

Modified Paths

Diff

Modified: trunk/Tools/ChangeLog (92146 => 92147)


--- trunk/Tools/ChangeLog	2011-08-01 22:09:24 UTC (rev 92146)
+++ trunk/Tools/ChangeLog	2011-08-01 22:22:27 UTC (rev 92147)
@@ -1,3 +1,24 @@
+2011-08-01  Dimitri Glazkov  <dglaz...@chromium.org>
+
+        Teach TestExpectationSerializer about parsed expectations.
+        https://bugs.webkit.org/show_bug.cgi?id=65444
+
+        This is a bit largish in size, but the essentials are:
+        * TestExpectationSerializer, given a parsed TestExpectationLine, can now spit out a pretty string.
+        * We now store original content of the expectation line on TestExpectationLine.
+        * Lots of tests.
+
+        Reviewed by Adam Barth.
+
+        * Scripts/webkitpy/layout_tests/models/test_configuration.py: Fixed an issue where we didn't
+            populate macros correctly, also fixed an issue where we incorrectly returned an empty list
+            for all configurations.
+        * Scripts/webkitpy/layout_tests/models/test_configuration_unittest.py: Added tests for those.
+        * Scripts/webkitpy/layout_tests/models/test_expectations.py: Removed vestiges of code long gone,
+            refactored TestExpectationsSerializer to recognize and correctly serialize parsed TestExpectationLine instances,
+            changed to store and use TestExpectationLine.original_string.
+        * Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py: Added tests.
+
 2011-08-01  Adam Barth  <aba...@webkit.org>
 
         Remove unused functionality from gardeningserver

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


--- trunk/Tools/Scripts/webkitpy/layout_tests/models/test_configuration.py	2011-08-01 22:09:24 UTC (rev 92146)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/models/test_configuration.py	2011-08-01 22:22:27 UTC (rev 92147)
@@ -74,15 +74,18 @@
             for category, specifier in test_configuration.items():
                 self.add_specifier(category, specifier)
 
+        self.add_macros(macros)
+
+    def add_specifier(self, category, specifier):
+        self._specifier_to_category[specifier] = category
+
+    def add_macros(self, macros):
         if not macros:
             return
         # Assume well-formed macros.
         for macro, specifier_list in macros.items():
             self.add_specifier(self.category_for_specifier(specifier_list[0]), macro)
 
-    def add_specifier(self, category, specifier):
-        self._specifier_to_category[specifier] = category
-
     @classmethod
     def category_priority(cls, category):
         return TestConfiguration.category_order().index(category)
@@ -133,6 +136,11 @@
                 if len(set_by_category) == 1 and self._specifier_sorter.category_priority(category) > self._specifier_sorter.specifier_priority(specifier):
                     self._junk_specifier_combinations[specifier] = set_by_category
 
+        self._specifier_sorter.add_macros(configuration_macros)
+
+    def specifier_sorter(self):
+        return self._specifier_sorter
+
     def _expand_macros(self, specifier):
         expanded_specifiers = self._configuration_macros.get(specifier)
         return expanded_specifiers or [specifier]
@@ -170,7 +178,7 @@
 
         # Easy out: if the set is all configurations, the modifier is empty.
         if len(test_configuration_set) == len(self._all_test_configurations):
-            return []
+            return [[]]
 
         # 1) Build a list of specifier sets, discarding specifiers that don't add value.
         specifiers_list = []

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


--- trunk/Tools/Scripts/webkitpy/layout_tests/models/test_configuration_unittest.py	2011-08-01 22:09:24 UTC (rev 92146)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/models/test_configuration_unittest.py	2011-08-01 22:22:27 UTC (rev 92147)
@@ -130,6 +130,13 @@
         self.assertEquals(sorter.category_for_specifier('one'), 'version')
         self.assertEquals(sorter.category_for_specifier('renaissance'), 'architecture')
 
+    def test_add_macros(self):
+        sorter = SpecifierSorter(self._all_test_configurations)
+        sorter.add_macros(MOCK_MACROS)
+        self.assertEquals(sorter.category_for_specifier('mac'), 'version')
+        self.assertEquals(sorter.category_for_specifier('win'), 'version')
+        self.assertEquals(sorter.category_for_specifier('x86'), 'architecture')
+
     def test_category_priority(self):
         sorter = SpecifierSorter(self._all_test_configurations)
         self.assertEquals(sorter.category_priority('version'), 0)
@@ -258,7 +265,8 @@
     def test_to_specifier_lists(self):
         converter = TestConfigurationConverter(self._all_test_configurations)
 
-        self.assertEquals(converter.to_specifiers_list(set(self._all_test_configurations)), [])
+        self.assertEquals(converter.to_specifiers_list(set(self._all_test_configurations)), [[]])
+        self.assertEquals(converter.to_specifiers_list(set()), [])
 
         configs_to_match = set([
             TestConfiguration(None, 'xp', 'x86', 'release', 'gpu'),
@@ -358,3 +366,8 @@
             TestConfiguration(None, 'snowleopard', 'x86', 'release', 'gpu'),
         ])
         self.assertEquals(converter.to_specifiers_list(configs_to_match), [set(['win', 'mac', 'release', 'gpu'])])
+
+    def test_specifier_converter_access(self):
+        specifier_sorter = TestConfigurationConverter(self._all_test_configurations, MOCK_MACROS).specifier_sorter()
+        self.assertEquals(specifier_sorter.category_for_specifier('snowleopard'), 'version')
+        self.assertEquals(specifier_sorter.category_for_specifier('mac'), 'version')

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py (92146 => 92147)


--- trunk/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py	2011-08-01 22:09:24 UTC (rev 92146)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py	2011-08-01 22:22:27 UTC (rev 92147)
@@ -52,10 +52,7 @@
 (PASS, FAIL, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, TIMEOUT, CRASH, SKIP, WONTFIX,
  SLOW, REBASELINE, MISSING, FLAKY, NOW, NONE) = range(16)
 
-# Test expectation file update action constants
-(NO_CHANGE, REMOVE_TEST, REMOVE_PLATFORM, ADD_PLATFORMS_EXCEPT_THIS) = range(4)
 
-
 def result_was_expected(result, expected_results, test_needs_rebaselining, test_is_skipped):
     """Returns whether we got a result we were expecting.
     Args:
@@ -124,28 +121,56 @@
 
 class TestExpectationSerializer:
     """Provides means of serializing TestExpectationLine instances."""
-    @classmethod
-    def to_string(cls, expectation):
+    def __init__(self, test_configuration_converter):
+        self._test_configuration_converter = test_configuration_converter
+        self._parsed_expectation_to_string = dict([[parsed_expectation, expectation_string] for expectation_string, parsed_expectation in TestExpectations.EXPECTATIONS.items()])
+
+    def to_string(self, expectation_line):
+        if expectation_line.is_malformed():
+            return expectation_line.original_string or ''
+
+        if expectation_line.name is None:
+            return '' if expectation_line.comment is None else "//%s" % expectation_line.comment
+
+        if expectation_line.parsed_bug_modifier:
+            specifiers_list = self._test_configuration_converter.to_specifiers_list(expectation_line.matching_configurations)
+            result = []
+            for specifiers in specifiers_list:
+                modifiers = self._parsed_modifier_string(expectation_line, specifiers)
+                expectations = self._parsed_expectations_string(expectation_line)
+                result.append(self._format_result(modifiers, expectation_line.name, expectations, expectation_line.comment))
+            return "\n".join(result)
+
+        return self._format_result(" ".join(expectation_line.modifiers), expectation_line.name, " ".join(expectation_line.expectations), expectation_line.comment)
+
+    def _parsed_expectations_string(self, expectation_line):
         result = []
-        if expectation.is_malformed():
-            result.append(expectation.comment)
-        else:
-            if expectation.name is None:
-                if expectation.comment is not None:
-                    result.append('//')
-                    result.append(expectation.comment)
-            else:
-                result.append("%s : %s = %s" % (" ".join(expectation.modifiers).upper(), expectation.name, " ".join(expectation.expectations).upper()))
-                if expectation.comment is not None:
-                    result.append(" //%s" % (expectation.comment))
+        for index in TestExpectations.EXPECTATION_ORDER:
+            if index in expectation_line.parsed_expectations:
+                result.append(self._parsed_expectation_to_string[index])
+        return ' '.join(result)
 
-        return ''.join(result)
+    def _parsed_modifier_string(self, expectation_line, specifiers):
+        result = []
+        if expectation_line.parsed_bug_modifier:
+            result.append(expectation_line.parsed_bug_modifier)
+        result.extend(expectation_line.parsed_modifiers)
+        result.extend(self._test_configuration_converter.specifier_sorter().sort_specifiers(specifiers))
+        return ' '.join(result)
 
     @classmethod
-    def list_to_string(cls, expectations):
-        return "\n".join([TestExpectationSerializer.to_string(expectation) for expectation in expectations])
+    def _format_result(cls, modifiers, name, expectations, comment):
+        result = "%s : %s = %s" % (modifiers.upper(), name, expectations.upper())
+        if comment is not None:
+            result += " //%s" % comment
+        return result
 
+    @classmethod
+    def list_to_string(cls, expectations, test_configuration_converter):
+        serializer = cls(test_configuration_converter)
+        return "\n".join([serializer.to_string(expectation) for expectation in expectations])
 
+
 class TestExpectationParser:
     """Provides parsing facilities for lines in the test_expectation.txt file."""
 
@@ -264,6 +289,7 @@
 
         """
         expectation_line = TestExpectationLine()
+        expectation_line.original_string = expectation_string
         expectation_line.line_number = line_number
         comment_index = expectation_string.find("//")
         if comment_index == -1:
@@ -283,9 +309,7 @@
             if len(test_and_expectation) != 2:
                 expectation_line.errors.append("Missing expectations" if len(test_and_expectation) < 2 else "Extraneous '='")
 
-        if expectation_line.is_malformed():
-            expectation_line.comment = expectation_string
-        else:
+        if not expectation_line.is_malformed():
             expectation_line.modifiers = cls._split_space_separated(parts[0])
             expectation_line.name = test_and_expectation[0].strip()
             expectation_line.expectations = cls._split_space_separated(test_and_expectation[1])
@@ -314,6 +338,7 @@
 
     def __init__(self):
         """Initializes a blank-line equivalent of an expectation."""
+        self.original_string = None
         self.line_number = None
         self.name = None
         self.path = None
@@ -654,6 +679,7 @@
         self._is_lint_mode = is_lint_mode
         self._model = TestExpectationsModel()
         self._parser = TestExpectationParser(port, tests, is_lint_mode)
+        self._test_configuration_converter = TestConfigurationConverter(port.all_test_configurations(), port.configuration_specifier_macros())
 
         self._expectations = TestExpectationParser.tokenize_list(expectations)
         self._add_expectations(self._expectations, overrides_allowed=False)
@@ -736,9 +762,9 @@
         warnings = []
         for expectation in self._expectations:
             for error in expectation.errors:
-                errors.append("Line:%s %s %s" % (expectation.line_number, error, expectation.name if expectation.expectations else expectation.comment))
+                errors.append("Line:%s %s %s" % (expectation.line_number, error, expectation.name if expectation.expectations else expectation.original_string))
             for warning in expectation.warnings:
-                warnings.append("Line:%s %s %s" % (expectation.line_number, warning, expectation.name if expectation.expectations else expectation.comment))
+                warnings.append("Line:%s %s %s" % (expectation.line_number, warning, expectation.name if expectation.expectations else expectation.original_string))
 
         if len(errors) or len(warnings):
             _log.error("FAILURES FOR %s" % str(self._test_config))
@@ -769,7 +795,7 @@
         def without_rebaseline_modifier(expectation):
             return not (not expectation.is_malformed() and expectation.name in tests and "rebaseline" in expectation.modifiers)
 
-        return TestExpectationSerializer.list_to_string(filter(without_rebaseline_modifier, self._expectations))
+        return TestExpectationSerializer.list_to_string(filter(without_rebaseline_modifier, self._expectations), self._test_configuration_converter)
 
     def _add_expectations(self, expectation_list, overrides_allowed):
         for expectation_line in expectation_list:

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py (92146 => 92147)


--- trunk/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py	2011-08-01 22:09:24 UTC (rev 92146)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py	2011-08-01 22:22:27 UTC (rev 92147)
@@ -31,6 +31,7 @@
 
 from webkitpy.layout_tests import port
 from webkitpy.layout_tests.port import base
+from webkitpy.layout_tests.models.test_configuration import *
 from webkitpy.layout_tests.models.test_expectations import *
 
 class FunctionsTest(unittest.TestCase):
@@ -388,13 +389,11 @@
     def test_tokenize_missing_colon(self):
         expectation = TestExpectationParser.tokenize('Qux.')
         self.assertEqual(expectation.is_malformed(), True)
-        self.assertEqual(expectation.comment, 'Qux.')
         self.assertEqual(str(expectation.errors), '["Missing a \':\'"]')
 
     def test_tokenize_extra_colon(self):
         expectation = TestExpectationParser.tokenize('FOO : : bar')
         self.assertEqual(expectation.is_malformed(), True)
-        self.assertEqual(expectation.comment, 'FOO : : bar')
         self.assertEqual(str(expectation.errors), '["Extraneous \':\'"]')
 
     def test_tokenize_empty_comment(self):
@@ -412,13 +411,11 @@
     def test_tokenize_missing_equal(self):
         expectation = TestExpectationParser.tokenize('FOO : bar')
         self.assertEqual(expectation.is_malformed(), True)
-        self.assertEqual(expectation.comment, 'FOO : bar')
         self.assertEqual(str(expectation.errors), "['Missing expectations\']")
 
     def test_tokenize_extra_equal(self):
         expectation = TestExpectationParser.tokenize('FOO : bar = BAZ = Qux.')
         self.assertEqual(expectation.is_malformed(), True)
-        self.assertEqual(expectation.comment, 'FOO : bar = BAZ = Qux.')
         self.assertEqual(str(expectation.errors), '["Extraneous \'=\'"]')
 
     def test_tokenize_valid(self):
@@ -455,39 +452,83 @@
 
 
 class TestExpectationSerializerTests(unittest.TestCase):
+    def __init__(self, testFunc):
+        test_port = port.get('test-win-xp', None)
+        self._serializer = TestExpectationSerializer(TestConfigurationConverter(test_port.all_test_configurations(), test_port.configuration_specifier_macros()))
+        unittest.TestCase.__init__(self, testFunc)
+
     def assert_round_trip(self, in_string, expected_string=None):
         expectation = TestExpectationParser.tokenize(in_string)
         if expected_string is None:
             expected_string = in_string
-        self.assertEqual(expected_string, TestExpectationSerializer.to_string(expectation))
+        self.assertEqual(expected_string, self._serializer.to_string(expectation))
 
     def assert_list_round_trip(self, in_string, expected_string=None):
         expectations = TestExpectationParser.tokenize_list(in_string)
         if expected_string is None:
             expected_string = in_string
-        self.assertEqual(expected_string, TestExpectationSerializer.list_to_string(expectations))
+        self.assertEqual(expected_string, TestExpectationSerializer.list_to_string(expectations, SpecifierSorter()))
 
-    def assert_to_string(self, expectation, expected_string):
-        self.assertEqual(TestExpectationSerializer.to_string(expectation), expected_string)
+    def test_unparsed_to_string(self):
+        expectation = TestExpectationLine()
 
-    def test_string_serializer(self):
-        expectation = TestExpectationLine()
-        self.assert_to_string(expectation, '')
+        self.assertEqual(self._serializer.to_string(expectation), '')
         expectation.comment = 'Qux.'
-        self.assert_to_string(expectation, '//Qux.')
+        self.assertEqual(self._serializer.to_string(expectation), '//Qux.')
         expectation.name = 'bar'
-        self.assert_to_string(expectation, ' : bar =  //Qux.')
+        self.assertEqual(self._serializer.to_string(expectation), ' : bar =  //Qux.')
         expectation.modifiers = ['foo']
-        self.assert_to_string(expectation, 'FOO : bar =  //Qux.')
+        self.assertEqual(self._serializer.to_string(expectation), 'FOO : bar =  //Qux.')
         expectation.expectations = ['bAz']
-        self.assert_to_string(expectation, 'FOO : bar = BAZ //Qux.')
+        self.assertEqual(self._serializer.to_string(expectation), 'FOO : bar = BAZ //Qux.')
         expectation.expectations = ['bAz1', 'baZ2']
-        self.assert_to_string(expectation, 'FOO : bar = BAZ1 BAZ2 //Qux.')
+        self.assertEqual(self._serializer.to_string(expectation), 'FOO : bar = BAZ1 BAZ2 //Qux.')
         expectation.modifiers = ['foo1', 'foO2']
-        self.assert_to_string(expectation, 'FOO1 FOO2 : bar = BAZ1 BAZ2 //Qux.')
+        self.assertEqual(self._serializer.to_string(expectation), 'FOO1 FOO2 : bar = BAZ1 BAZ2 //Qux.')
         expectation.errors.append('Oh the horror.')
-        self.assert_to_string(expectation, 'Qux.')
+        self.assertEqual(self._serializer.to_string(expectation), '')
+        expectation.original_string = 'Yes it is!'
+        self.assertEqual(self._serializer.to_string(expectation), 'Yes it is!')
 
+    def test_parsed_to_string(self):
+        expectation_line = TestExpectationLine()
+        expectation_line.parsed_bug_modifier = 'BUGX'
+        expectation_line.name = 'test/name/for/realz.html'
+        expectation_line.parsed_expectations = set([IMAGE])
+        self.assertEqual(self._serializer.to_string(expectation_line), '')
+        expectation_line.matching_configurations = set([TestConfiguration(None, 'xp', 'x86', 'release', 'cpu')])
+        self.assertEqual(self._serializer.to_string(expectation_line), 'BUGX XP RELEASE CPU : test/name/for/realz.html = IMAGE')
+        expectation_line.matching_configurations = set([TestConfiguration(None, 'xp', 'x86', 'release', 'cpu'), TestConfiguration(None, 'xp', 'x86', 'release', 'gpu')])
+        self.assertEqual(self._serializer.to_string(expectation_line), 'BUGX XP RELEASE : test/name/for/realz.html = IMAGE')
+        expectation_line.matching_configurations = set([TestConfiguration(None, 'xp', 'x86', 'release', 'cpu'), TestConfiguration(None, 'xp', 'x86', 'debug', 'gpu')])
+        self.assertEqual(self._serializer.to_string(expectation_line), 'BUGX XP RELEASE CPU : test/name/for/realz.html = IMAGE\nBUGX XP DEBUG GPU : test/name/for/realz.html = IMAGE')
+
+    def test_parsed_expectations_string(self):
+        expectation_line = TestExpectationLine()
+        expectation_line.parsed_expectations = set([])
+        self.assertEqual(self._serializer._parsed_expectations_string(expectation_line), '')
+        expectation_line.parsed_expectations = set([IMAGE_PLUS_TEXT])
+        self.assertEqual(self._serializer._parsed_expectations_string(expectation_line), 'image+text')
+        expectation_line.parsed_expectations = set([PASS, FAIL])
+        self.assertEqual(self._serializer._parsed_expectations_string(expectation_line), 'pass fail')
+        expectation_line.parsed_expectations = set([FAIL, PASS])
+        self.assertEqual(self._serializer._parsed_expectations_string(expectation_line), 'pass fail')
+
+    def test_parsed_modifier_string(self):
+        expectation_line = TestExpectationLine()
+        expectation_line.parsed_bug_modifier = 'garden-o-matic'
+        expectation_line.parsed_modifiers = ['for', 'the']
+        self.assertEqual(self._serializer._parsed_modifier_string(expectation_line, []), 'garden-o-matic for the')
+        self.assertEqual(self._serializer._parsed_modifier_string(expectation_line, ['win']), 'garden-o-matic for the win')
+        expectation_line.parsed_bug_modifier = ''
+        expectation_line.parsed_modifiers = []
+        self.assertEqual(self._serializer._parsed_modifier_string(expectation_line, []), '')
+        self.assertEqual(self._serializer._parsed_modifier_string(expectation_line, ['win']), 'win')
+
+    def test_format_result(self):
+        self.assertEqual(TestExpectationSerializer._format_result('modifiers', 'name', 'expectations', 'comment'), 'MODIFIERS : name = EXPECTATIONS //comment')
+        self.assertEqual(TestExpectationSerializer._format_result('modifiers', 'name', 'expectations', None), 'MODIFIERS : name = EXPECTATIONS')
+
     def test_string_roundtrip(self):
         self.assert_round_trip('')
         self.assert_round_trip('FOO')
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to