Changeset 91166 in webkit


Ignore:
Timestamp:
Jul 17, 2011 12:38:01 AM (13 years ago)
Author:
Dimitri Glazkov
Message:

Rename ModifierMatcher to SpecificityCalculator.
https://bugs.webkit.org/show_bug.cgi?id=64660

It's a little longer than before, but it is much clearer.

Reviewed by Adam Barth.

  • Scripts/webkitpy/layout_tests/models/test_expectations.py: Renamed and adjusted

all callsites, also rewrote the comments.

  • Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py: Adjusted callsites

and renamed tests.

Location:
trunk/Tools
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r91144 r91166  
     12011-07-17  Dimitri Glazkov  <dglazkov@chromium.org>
     2
     3        Rename ModifierMatcher to SpecificityCalculator.
     4        https://bugs.webkit.org/show_bug.cgi?id=64660
     5
     6        It's a little longer than before, but it is much clearer.
     7
     8        Reviewed by Adam Barth.
     9
     10        * Scripts/webkitpy/layout_tests/models/test_expectations.py: Renamed and adjusted
     11            all callsites, also rewrote the comments.
     12        * Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py: Adjusted callsites
     13            and renamed tests.
     14
    1152011-07-15  Adam Barth  <abarth@webkit.org>
    216
  • trunk/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py

    r91124 r91166  
    177177    def __init__(self, port, test_config, full_test_list, allow_rebaseline_modifier):
    178178        self._port = port
    179         self._matcher = ModifierMatcher(test_config)
     179        self._specificity_calculator = SpecificityCalculator(test_config)
    180180        self._full_test_list = full_test_list
    181181        self._allow_rebaseline_modifier = allow_rebaseline_modifier
    182182
    183183    def parse(self, expectation_line):
    184         self._matcher.match(expectation_line)
     184        self._specificity_calculator.calculate(expectation_line)
    185185        self._check_semantics(expectation_line)
    186186
    187         if expectation_line.num_matches == ModifierMatcher.NO_MATCH:
     187        if expectation_line.specificity == SpecificityCalculator.INVALID:
    188188            return
    189189
     
    330330        self.parsed_expectations = set()
    331331        self.comment = None
    332         self.num_matches = ModifierMatcher.NO_MATCH
     332        self.specificity = SpecificityCalculator.INVALID
    333333        self.matching_tests = []
    334334        self.errors = []
     
    498498            than this path does
    499499        """
    500         # FIXME: See comment below about matching test configs and num_matches.
     500        # FIXME: See comment below about matching test configs and specificity.
    501501        if not self.has_test(test):
    502502            # We've never seen this test before.
     
    531531        # However, we currently view these as errors. If we decide to make
    532532        # this policy permanent, we can probably simplify this code
    533         # and the ModifierMatcher code a fair amount.
     533        # and the SpecificityCalculator code a fair amount.
    534534        #
    535535        # To use the "more modifiers wins" policy, change the errors for overrides
    536536        # to be warnings and return False".
    537537
    538         if prev_expectation_line.num_matches == expectation_line.num_matches:
     538        if prev_expectation_line.specificity == expectation_line.specificity:
    539539            expectation_line.errors.append('Duplicate or ambiguous %s.' % expectation_source)
    540540            return True
    541541
    542         if prev_expectation_line.num_matches < expectation_line.num_matches:
     542        if prev_expectation_line.specificity < expectation_line.specificity:
    543543            expectation_line.errors.append('More specific entry on line %d overrides line %d' % (lineno, prev_lineno))
    544544            # FIXME: return False if we want more specific to win.
     
    807807
    808808
    809 class ModifierMatchResult(object):
     809class SpecificityCalculation(object):
    810810    def __init__(self, modifiers):
    811         self.num_matches = ModifierMatcher.NO_MATCH
     811        self.specificity = SpecificityCalculator.INVALID
    812812        self._modifiers = modifiers
    813813        self._matched_modifiers = []
     
    816816
    817817
    818 class ModifierMatcher(object):
     818class SpecificityCalculator(object):
    819819
    820820    """
    821     This class manages the interpretation of the "modifiers" for a given
    822     line in the expectations file. Modifiers are the tokens that appear to the
    823     left of the colon on a line. For example, "BUG1234", "DEBUG", and "WIN" are
    824     all modifiers. This class gets what the valid modifiers are, and which
    825     modifiers are allowed to exist together on a line, from the
    826     TestConfiguration object that is passed in to the call.
    827 
    828     This class detects *intra*-line errors like unknown modifiers, but
    829     does not detect *inter*-line modifiers like duplicate expectations.
    830 
    831     More importantly, this class is also used to determine if a given line
    832     matches the port in question. Matches are ranked according to the number
    833     of modifiers that match on a line. A line with no modifiers matches
     821    This class determines how specific are the modifiers for a given
     822    TestExpectationLine. Some modifiers describe a test configuration for which this
     823    test expectation is applicable. There is a degree of specificity for these modifiers.
     824
     825    For example, 'XP RELEASE CPU' is very specific, because it limits applicable test configuration to
     826    Windows XP system in Release mode, with CPU-backed graphics.
     827
     828    On the other hand, '' (empty modifier) makes the test applicable to any test configuration.
     829
     830    This class finds such modifiers, interprets their meaning and determines specificity of
     831    a given test expectation.
     832
     833    The specificity is determined as a count of modifiers that match. A line with no modifiers matches
    834834    everything and has a score of zero. A line with one modifier matches only
    835835    ports that have that modifier and gets a score of 1, and so one. Ports
     
    854854    supports "macros" that are expanded prior to interpretation, and "ignore
    855855    regexes" that can be used to skip over modifiers like the BUG* modifiers.
     856
     857    This class also detects errors in this test expectation, like unknown modifiers,
     858    invalid modifier combinations, and duplicate modifiers.
    856859    """
    857860    MACROS = {
     
    866869    DUPLICATE_REGEXES_ALLOWED = ['bug\w+']
    867870
    868     # Magic value returned when the modifiers don't match.
    869     NO_MATCH = -1
     871    # Magic value returned when the modifiers don't match the configuration at all.
     872    INVALID = -1
    870873
    871874    # FIXME: The code currently doesn't detect combinations of modifiers
    872875    # that are syntactically valid but semantically invalid, like
    873     # 'MAC XP'. See ModifierMatchTest.test_invalid_combinations() in the
     876    # 'MAC XP'. See SpecificityCalculatorTest.test_invalid_combinations() in the
    874877    # _unittest.py file.
    875878
    876879    def __init__(self, test_config):
    877         """Initialize a ModifierMatcher argument with the TestConfiguration it
     880        """Initialize a SpecificityCalculator argument with the TestConfiguration it
    878881        should be matched against."""
    879882        self.test_config = test_config
     
    895898                self._all_modifiers.add(modifier)
    896899
    897     def match(self, expectation_line):
     900    def calculate(self, expectation_line):
    898901        """Checks a expectation.modifiers against the config set in the constructor.
    899902        Options may be either actual modifier strings, "macro" strings
     
    901904        to be ignored. All of the modifiers must be passed in in lower case.
    902905
    903         Returns the number of matching categories, or NO_MATCH (-1) if it
     906        Returns specificity relative to the test configuration, or INVALID (-1) if it
    904907        doesn't match or there were errors found. Matches are prioritized
    905908        by the number of matching categories, because the more specific
     
    907910        """
    908911        old_error_count = len(expectation_line.errors)
    909         result = ModifierMatchResult(expectation_line.modifiers)
     912        result = SpecificityCalculation(expectation_line.modifiers)
    910913        self._parse(expectation_line, result)
    911914        if old_error_count == len(expectation_line.errors):
    912915            self._count_matches(result)
    913         expectation_line.num_matches = result.num_matches
     916        expectation_line.specificity = result.specificity
    914917
    915918    def _parse(self, expectation_line, result):
     
    964967        """Returns the number of modifiers that match the test config."""
    965968        categorized_modifiers = self._group_by_category(result._matched_modifiers)
    966         result.num_matches = 0
     969        result.specificity = 0
    967970        for category, modifier in self.test_config.items():
    968971            if category in categorized_modifiers:
    969972                if modifier in categorized_modifiers[category]:
    970                     result.num_matches += 1
     973                    result.specificity += 1
    971974                else:
    972                     result.num_matches = self.NO_MATCH
     975                    result.specificity = self.INVALID
    973976                    return
    974977
  • trunk/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py

    r91103 r91166  
    385385
    386386
    387 class ModifierTests(unittest.TestCase):
     387class SpecificityCalculatorTests(unittest.TestCase):
    388388    def setUp(self):
    389389        port_obj = port.get('test-win-xp', None)
    390390        self.config = port_obj.test_configuration()
    391         self.matcher = ModifierMatcher(self.config)
    392 
    393     def match(self, modifiers, expected_num_matches=-1, values=None, num_errors=0):
    394         matcher = self.matcher
    395         if values:
    396             matcher = ModifierMatcher(self.FakeTestConfiguration(values))
     391        self.calculator = SpecificityCalculator(self.config)
     392
     393    def assert_specificity(self, modifiers, expected_specificity=-1, num_errors=0):
    397394        expectation = TestExpectationLine()
    398395        expectation.modifiers = modifiers
    399         matcher.match(expectation)
     396        self.calculator.calculate(expectation)
    400397        self.assertEqual(len(expectation.warnings), 0)
    401398        self.assertEqual(len(expectation.errors), num_errors)
    402         self.assertEqual(expectation.num_matches, expected_num_matches,
     399        self.assertEqual(expectation.specificity, expected_specificity,
    403400             'match(%s, %s) returned -> %d, expected %d' %
    404401             (modifiers, str(self.config.values()),
    405               expectation.num_matches, expected_num_matches))
     402              expectation.specificity, expected_specificity))
    406403
    407404    def test_bad_match_modifier(self):
    408         self.match(['foo'], num_errors=1)
     405        self.assert_specificity(['foo'], num_errors=1)
    409406
    410407    def test_none(self):
    411         self.match([], 0)
     408        self.assert_specificity([], 0)
    412409
    413410    def test_one(self):
    414         self.match(['xp'], 1)
    415         self.match(['win'], 1)
    416         self.match(['release'], 1)
    417         self.match(['cpu'], 1)
    418         self.match(['x86'], 1)
    419         self.match(['leopard'], -1)
    420         self.match(['gpu'], -1)
    421         self.match(['debug'], -1)
     411        self.assert_specificity(['xp'], 1)
     412        self.assert_specificity(['win'], 1)
     413        self.assert_specificity(['release'], 1)
     414        self.assert_specificity(['cpu'], 1)
     415        self.assert_specificity(['x86'], 1)
     416        self.assert_specificity(['leopard'], -1)
     417        self.assert_specificity(['gpu'], -1)
     418        self.assert_specificity(['debug'], -1)
    422419
    423420    def test_two(self):
    424         self.match(['xp', 'release'], 2)
    425         self.match(['win7', 'release'], -1)
    426         self.match(['win7', 'xp'], 1)
     421        self.assert_specificity(['xp', 'release'], 2)
     422        self.assert_specificity(['win7', 'release'], -1)
     423        self.assert_specificity(['win7', 'xp'], 1)
    427424
    428425    def test_three(self):
    429         self.match(['win7', 'xp', 'release'], 2)
    430         self.match(['xp', 'debug', 'x86'], -1)
    431         self.match(['xp', 'release', 'x86'], 3)
    432         self.match(['xp', 'cpu', 'release'], 3)
     426        self.assert_specificity(['win7', 'xp', 'release'], 2)
     427        self.assert_specificity(['xp', 'debug', 'x86'], -1)
     428        self.assert_specificity(['xp', 'release', 'x86'], 3)
     429        self.assert_specificity(['xp', 'cpu', 'release'], 3)
    433430
    434431    def test_four(self):
    435         self.match(['xp', 'release', 'cpu', 'x86'], 4)
    436         self.match(['win7', 'xp', 'release', 'cpu'], 3)
    437         self.match(['win7', 'xp', 'debug', 'cpu'], -1)
     432        self.assert_specificity(['xp', 'release', 'cpu', 'x86'], 4)
     433        self.assert_specificity(['win7', 'xp', 'release', 'cpu'], 3)
     434        self.assert_specificity(['win7', 'xp', 'debug', 'cpu'], -1)
    438435
    439436    def test_case_insensitivity(self):
    440         self.match(['Win'], num_errors=1)
    441         self.match(['WIN'], num_errors=1)
    442         self.match(['win'], 1)
     437        self.assert_specificity(['Win'], num_errors=1)
     438        self.assert_specificity(['WIN'], num_errors=1)
     439        self.assert_specificity(['win'], 1)
    443440
    444441    def test_duplicates(self):
    445         self.match(['release', 'release'], num_errors=1)
    446         self.match(['win', 'xp'], num_errors=1)
    447         self.match(['xp', 'xp'], num_errors=1)
    448         self.match(['xp', 'release', 'xp', 'release'], num_errors=2)
    449         self.match(['rebaseline', 'rebaseline'], num_errors=1)
     442        self.assert_specificity(['release', 'release'], num_errors=1)
     443        self.assert_specificity(['win', 'xp'], num_errors=1)
     444        self.assert_specificity(['xp', 'xp'], num_errors=1)
     445        self.assert_specificity(['xp', 'release', 'xp', 'release'], num_errors=2)
     446        self.assert_specificity(['rebaseline', 'rebaseline'], num_errors=1)
    450447
    451448    def test_unknown_modifier(self):
    452         self.match(['vms'], num_errors=1)
     449        self.assert_specificity(['vms'], num_errors=1)
    453450
    454451    def test_duplicate_bugs(self):
    455452        # BUG* regexes can appear multiple times.
    456         self.match(['bugfoo', 'bugbar'], 0)
     453        self.assert_specificity(['bugfoo', 'bugbar'], 0)
    457454
    458455    def test_regexes_are_ignored(self):
    459         self.match(['bug123xy', 'rebaseline', 'wontfix', 'slow', 'skip'], 0)
     456        self.assert_specificity(['bug123xy', 'rebaseline', 'wontfix', 'slow', 'skip'], 0)
    460457
    461458    def test_none_is_invalid(self):
    462         self.match(['none'], num_errors=1)
     459        self.assert_specificity(['none'], num_errors=1)
    463460
    464461
Note: See TracChangeset for help on using the changeset viewer.