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')