Changeset 129051 in webkit


Ignore:
Timestamp:
Sep 19, 2012 3:29:45 PM (12 years ago)
Author:
dpranke@chromium.org
Message:

implement first part of support for the new TestExpectations syntax
https://bugs.webkit.org/show_bug.cgi?id=96569

Reviewed by Ryosuke Niwa.

This patch implements support for parsing a line of the new
format for the TestExpectations file and converting it back into
the old format for compatibility. This routine is not yet used
by anything.

The new format is documented at:

http://trac.webkit.org/wiki/TestExpectations

but, in short:

[bugs] [ "modifiers?" ] test_name [ "expectations?" ]

  • Comments are indicated with "#" instead of ""
  • If no expectations are specified we default to Skip for compatibility with the Skipped files (these two changes make Skipped files a subset of TestExpectations files)
  • All of the tokens are now CamelCase instead of ALLCAPS.
  • FAIL -> Failure
  • IMAGE -> ImageOnlyFailure
  • WONTFIX -> WontFix
  • modifiers refer to just the platforms and configurations (release/debug) that the line applies to.
  • WontFix, Rebaseline, Slow, and Skip move to the right-hand side as expectations
  • expectations will typically be written out in lexicographic order
  • We use webkit.org/b/12345, crbug.com/12345, and Bug(dpranke) instead of BUGWK12345, BUGCR12345, and BUGDPRANKE.
  • Scripts/webkitpy/layout_tests/models/test_expectations.py:

(TestExpectationParser):
(TestExpectationParser._tokenize_line_using_new_format):

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

(NewExpectationSyntaxTests):
(NewExpectationSyntaxTests.assert_exp):
(NewExpectationSyntaxTests.test_bare_name):
(NewExpectationSyntaxTests.test_bare_name_and_bugs):
(NewExpectationSyntaxTests.test_comments):
(NewExpectationSyntaxTests.test_config_modifiers):
(NewExpectationSyntaxTests.test_unknown_config):
(NewExpectationSyntaxTests.test_unknown_expectation):
(NewExpectationSyntaxTests.test_skip):
(NewExpectationSyntaxTests.test_slow):
(NewExpectationSyntaxTests.test_wontfix):
(NewExpectationSyntaxTests.test_blank_line):
(NewExpectationSyntaxTests.test_warnings):

Location:
trunk/Tools
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r129047 r129051  
     12012-09-19  Dirk Pranke  <dpranke@chromium.org>
     2
     3        implement first part of support for the new TestExpectations syntax
     4        https://bugs.webkit.org/show_bug.cgi?id=96569
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        This patch implements support for parsing a line of the new
     9        format for the TestExpectations file and converting it back into
     10        the old format for compatibility. This routine is not yet used
     11        by anything.
     12
     13        The new format is documented at:
     14          http://trac.webkit.org/wiki/TestExpectations
     15
     16        but, in short:
     17
     18          [bugs] [ "[" modifiers "]" ] test_name [ "[" expectations "]" ]
     19
     20        - Comments are indicated with "#" instead of "//"
     21        - If no expectations are specified we default to Skip for
     22          compatibility with the Skipped files (these two changes make
     23          Skipped files a subset of TestExpectations files)
     24
     25        - All of the tokens are now CamelCase instead of ALLCAPS.
     26        - FAIL -> Failure
     27        - IMAGE -> ImageOnlyFailure
     28        - WONTFIX -> WontFix
     29        - modifiers refer to just the platforms and configurations
     30          (release/debug) that the line applies to.
     31        - WontFix, Rebaseline, Slow, and Skip move to the right-hand side as
     32          expectations
     33        - expectations will typically be written out in lexicographic order
     34        - We use webkit.org/b/12345, crbug.com/12345, and Bug(dpranke)
     35          instead of BUGWK12345, BUGCR12345, and BUGDPRANKE.
     36
     37        * Scripts/webkitpy/layout_tests/models/test_expectations.py:
     38        (TestExpectationParser):
     39        (TestExpectationParser._tokenize_line_using_new_format):
     40        * Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py:
     41        (NewExpectationSyntaxTests):
     42        (NewExpectationSyntaxTests.assert_exp):
     43        (NewExpectationSyntaxTests.test_bare_name):
     44        (NewExpectationSyntaxTests.test_bare_name_and_bugs):
     45        (NewExpectationSyntaxTests.test_comments):
     46        (NewExpectationSyntaxTests.test_config_modifiers):
     47        (NewExpectationSyntaxTests.test_unknown_config):
     48        (NewExpectationSyntaxTests.test_unknown_expectation):
     49        (NewExpectationSyntaxTests.test_skip):
     50        (NewExpectationSyntaxTests.test_slow):
     51        (NewExpectationSyntaxTests.test_wontfix):
     52        (NewExpectationSyntaxTests.test_blank_line):
     53        (NewExpectationSyntaxTests.test_warnings):
     54
    1552012-09-19  Dirk Pranke  <dpranke@chromium.org>
    256
  • trunk/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py

    r129047 r129051  
    255255        return expectation_line
    256256
     257    # FIXME: Update the original modifiers and remove this once the old syntax is gone.
     258    _configuration_tokens_list = [
     259        'Mac', 'SnowLeopard', 'Lion', 'MountainLion',
     260        'Win', 'XP', 'Vista', 'Win7',
     261        'Linux',
     262        'Android',
     263        'Release',
     264        'Debug',
     265    ]
     266
     267    _configuration_tokens = dict((token, token.upper()) for token in _configuration_tokens_list)
     268
     269    # Note: we can't distinguish audio failures or image+text failures from text-only failures.
     270    # FIXME: Update the original modifiers list and remove this once the old syntax is gone.
     271    _expectation_tokens = {
     272        'WontFix': 'WONTFIX',
     273        'Pass': 'PASS',
     274        'Failure': 'FAIL',
     275        'ImageOnlyFailure': 'IMAGE',
     276        'Crash': 'CRASH',
     277        'Timeout': 'TIMEOUT',
     278        'Slow': 'SLOW',
     279    }
     280
    257281    @classmethod
    258282    def _tokenize_line_using_new_format(cls, filename, expectation_string, line_number):
    259         # FIXME: implement :).
    260         raise NotImplementedError
     283        """Tokenizes a line from TestExpectations and returns an unparsed TestExpectationLine instance using the old format.
     284
     285        The new format for a test expectation line is:
     286
     287        [[bugs] [ "[" <configuration modifiers> "]" <name> [ "[" <expectations> "]" ["#" <comment>]
     288
     289        Any errant whitespace is not preserved.
     290
     291        """
     292        expectation_line = TestExpectationLine()
     293        expectation_line.filename = filename
     294        expectation_line.line_number = line_number
     295
     296        comment_index = expectation_string.find("#")
     297        if comment_index == -1:
     298            comment_index = len(expectation_string)
     299        else:
     300            expectation_line.comment = expectation_string[comment_index + 1:]
     301
     302        remaining_string = re.sub(r"\s+", " ", expectation_string[:comment_index].strip())
     303        if len(remaining_string) == 0:
     304            return expectation_line
     305
     306        # special-case parsing this so that we fail immediately instead of treating this as a test name
     307        if remaining_string.startswith('//'):
     308            expectation_line.warnings = ['use "#" instead of "//" for comments']
     309            return expectation_line
     310
     311        bugs = []
     312        modifiers = []
     313        name = None
     314        expectations = []
     315        warnings = []
     316
     317        WEBKIT_BUG_PREFIX = 'webkit.org/b/'
     318        CHROMIUM_BUG_PREFIX = 'crbug.com/'
     319        V8_BUG_PREFIX = 'code.google.com/p/v8/issues/detail?id='
     320
     321        tokens = remaining_string.split()
     322        state = 'start'
     323        for token in tokens:
     324            if (token.startswith(WEBKIT_BUG_PREFIX) or
     325                token.startswith(CHROMIUM_BUG_PREFIX) or
     326                token.startswith(V8_BUG_PREFIX) or
     327                token.startswith('Bug(')):
     328                if state != 'start':
     329                    warnings.append('"%s" is not at the start of the line.' % token)
     330                    break
     331                if token.startswith(WEBKIT_BUG_PREFIX):
     332                    bugs.append(token.replace(WEBKIT_BUG_PREFIX, 'BUGWK'))
     333                elif token.startswith(CHROMIUM_BUG_PREFIX):
     334                    bugs.append(token.replace(CHROMIUM_BUG_PREFIX, 'BUGCR'))
     335                elif token.startswith(V8_BUG_PREFIX):
     336                    bugs.append(token.replace(V8_BUG_PREFIX, 'BUGV8_'))
     337                else:
     338                    match = re.match('Bug\((\w+)\)$', token)
     339                    if not match:
     340                        warnings.append('unrecognized bug identifier "%s"' % token)
     341                        break
     342                    else:
     343                        bugs.append('BUG' + match.group(1).upper())
     344            elif token.startswith('BUG'):
     345                warnings.append('unrecognized old-style bug identifier "%s"' % token)
     346                break
     347            elif token == '[':
     348                if state == 'start':
     349                    state = 'configuration'
     350                elif state == 'name_found':
     351                    state = 'expectations'
     352                else:
     353                    warnings.append('unexpected "["')
     354                    break
     355            elif token == ']':
     356                if state == 'configuration':
     357                    state = 'name'
     358                elif state == 'expectations':
     359                    state = 'done'
     360                else:
     361                    warnings.append('unexpected "]"')
     362                    break
     363            elif token in ('//', ':', '='):
     364                warnings.append('"%s" is not legal in the new TestExpectations syntax.' % token)
     365                break
     366            elif state == 'configuration':
     367                modifiers.append(cls._configuration_tokens.get(token, token))
     368            elif state == 'expectations':
     369                if token in ('Rebaseline', 'Skip', 'Slow', 'WontFix'):
     370                    modifiers.append(token.upper())
     371                else:
     372                    expectations.append(cls._expectation_tokens.get(token, token))
     373            elif state == 'name_found':
     374                warnings.append('expecting "[", "#", or end of line instead of "%s"' % token)
     375                break
     376            else:
     377                name = token
     378                state = 'name_found'
     379
     380        if not warnings:
     381            if not name:
     382                warnings.append('Did not find a test name.')
     383            elif state not in ('name_found', 'done'):
     384                warnings.append('Missing a "]"')
     385
     386        if not expectations:
     387            if 'SKIP' not in modifiers and 'REBASELINE' not in modifiers and 'SLOW' not in modifiers:
     388                modifiers.append('SKIP')
     389            expectations = ['PASS']
     390
     391        # FIXME: expectation line should just store bugs and modifiers separately.
     392        expectation_line.modifiers = bugs + modifiers
     393        expectation_line.expectations = expectations
     394        expectation_line.name = name
     395        expectation_line.warnings = warnings
     396        return expectation_line
    261397
    262398    @classmethod
  • trunk/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py

    r129047 r129051  
    341341
    342342
     343class NewExpectationSyntaxTests(unittest.TestCase):
     344    def assert_exp(self, line, bugs=None, modifiers=None, expectations=None, warnings=None, comment=None, name='foo.html'):
     345        bugs = bugs or []
     346        modifiers = modifiers or []
     347        expectations = expectations or []
     348        warnings = warnings or []
     349        filename = 'TestExpectations'
     350        line_number = 1
     351        expectation_line = TestExpectationParser._tokenize_line_using_new_format(filename, line, line_number)
     352        self.assertEquals(expectation_line.warnings, warnings)
     353        self.assertEquals(expectation_line.name, name)
     354        self.assertEquals(expectation_line.filename, filename)
     355        self.assertEquals(expectation_line.line_number, line_number)
     356        if not warnings:
     357            self.assertEquals(expectation_line.modifiers, modifiers)
     358            self.assertEquals(expectation_line.expectations, expectations)
     359
     360    def test_bare_name(self):
     361        self.assert_exp('foo.html', modifiers=['SKIP'], expectations=['PASS'])
     362
     363    def test_bare_name_and_bugs(self):
     364        self.assert_exp('webkit.org/b/12345 foo.html', modifiers=['BUGWK12345', 'SKIP'], expectations=['PASS'])
     365        self.assert_exp('crbug.com/12345 foo.html', modifiers=['BUGCR12345', 'SKIP'], expectations=['PASS'])
     366        self.assert_exp('Bug(dpranke) foo.html', modifiers=['BUGDPRANKE', 'SKIP'], expectations=['PASS'])
     367        self.assert_exp('crbug.com/12345 crbug.com/34567 foo.html', modifiers=['BUGCR12345', 'BUGCR34567', 'SKIP'], expectations=['PASS'])
     368
     369    def test_comments(self):
     370        self.assert_exp("# comment", name=None, comment="# comment")
     371        self.assert_exp("foo.html # comment", comment="# comment", expectations=['PASS'], modifiers=['SKIP'])
     372
     373    def test_config_modifiers(self):
     374        self.assert_exp('[ Mac ] foo.html', modifiers=['MAC', 'SKIP'], expectations=['PASS'])
     375        self.assert_exp('[ Mac Vista ] foo.html', modifiers=['MAC', 'VISTA', 'SKIP'], expectations=['PASS'])
     376        self.assert_exp('[ Mac ] foo.html [ Failure ] ', modifiers=['MAC'], expectations=['FAIL'])
     377
     378    def test_unknown_config(self):
     379        self.assert_exp('[ Foo ] foo.html ', modifiers=['Foo', 'SKIP'], expectations=['PASS'])
     380
     381    def test_unknown_expectation(self):
     382        self.assert_exp('foo.html [ Audio ]', expectations=['Audio'])
     383
     384    def test_skip(self):
     385        self.assert_exp('foo.html [ Skip ]', modifiers=['SKIP'], expectations=['PASS'])
     386
     387    def test_slow(self):
     388        self.assert_exp('foo.html [ Slow ]', modifiers=['SLOW'], expectations=['PASS'])
     389
     390    def test_wontfix(self):
     391        self.assert_exp('foo.html [ WontFix ]', modifiers=['WONTFIX', 'SKIP'], expectations=['PASS'])
     392
     393    def test_blank_line(self):
     394        self.assert_exp('', name=None)
     395
     396    def test_warnings(self):
     397        self.assert_exp('[ Mac ]', warnings=['Did not find a test name.'], name=None)
     398
     399        self.assert_exp('[ [', warnings=['unexpected "["'], name=None)
     400        self.assert_exp('crbug.com/12345 ]', warnings=['unexpected "]"'], name=None)
     401
     402        self.assert_exp('foo.html crbug.com/12345 ]', warnings=['"crbug.com/12345" is not at the start of the line.'])
     403
     404
    343405class SemanticTests(Base):
    344406    def test_bug_format(self):
Note: See TracChangeset for help on using the changeset viewer.