webkitpy: move --lint-test-files code into its own module
authordpranke@chromium.org <dpranke@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Dec 2012 21:50:27 +0000 (21:50 +0000)
committerdpranke@chromium.org <dpranke@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Dec 2012 21:50:27 +0000 (21:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=105077

Reviewed by Eric Seidel.

It really didn't need to be in run_webkit_tests.py anymore.
This patch adds a new lint-test-expectations scripts to Tools/Scripts;
rwt --lint-test-files is still supported for backwards compatibility
for now.

* Scripts/lint-test-expectations: Added.
* Scripts/webkitpy/layout_tests/lint_test_expectations.py: Added.
(lint):
(main):
* Scripts/webkitpy/layout_tests/lint_test_expectations_unittest.py: Added.
(FakePort):
(FakePort.__init__):
(FakePort.test_configuration):
(FakePort.expectations_dict):
(FakePort.skipped_layout_tests):
(FakePort.all_test_configurations):
(FakePort.configuration_specifier_macros):
(FakePort.get_option):
(FakeFactory):
(FakeFactory.__init__):
(FakeFactory.get):
(FakeFactory.all_port_names):
(LintTest):
(LintTest.test_all_configurations):
(LintTest.test_lint_test_files):
(LintTest.test_lint_test_files__errors):
(MainTest):
(MainTest.test_success):
(MainTest.test_success.interrupting_lint):
(MainTest.test_success.successful_lint):
(MainTest.test_success.exception_raising_lint):
* Scripts/webkitpy/layout_tests/run_webkit_tests.py:
(main):
* Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py:
(StreamTestingMixin.assertNotEmpty):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@137942 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Tools/ChangeLog
Tools/Scripts/lint-test-expectations [new file with mode: 0755]
Tools/Scripts/webkitpy/layout_tests/lint_test_expectations.py [new file with mode: 0644]
Tools/Scripts/webkitpy/layout_tests/lint_test_expectations_unittest.py [new file with mode: 0644]
Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py

index 3c7323b..2879562 100644 (file)
@@ -1,3 +1,46 @@
+2012-12-17  Dirk Pranke  <dpranke@chromium.org>
+
+        webkitpy: move --lint-test-files code into its own module
+        https://bugs.webkit.org/show_bug.cgi?id=105077
+
+        Reviewed by Eric Seidel.
+
+        It really didn't need to be in run_webkit_tests.py anymore.
+        This patch adds a new lint-test-expectations scripts to Tools/Scripts;
+        rwt --lint-test-files is still supported for backwards compatibility
+        for now.
+
+        * Scripts/lint-test-expectations: Added.
+        * Scripts/webkitpy/layout_tests/lint_test_expectations.py: Added.
+        (lint):
+        (main):
+        * Scripts/webkitpy/layout_tests/lint_test_expectations_unittest.py: Added.
+        (FakePort):
+        (FakePort.__init__):
+        (FakePort.test_configuration):
+        (FakePort.expectations_dict):
+        (FakePort.skipped_layout_tests):
+        (FakePort.all_test_configurations):
+        (FakePort.configuration_specifier_macros):
+        (FakePort.get_option):
+        (FakeFactory):
+        (FakeFactory.__init__):
+        (FakeFactory.get):
+        (FakeFactory.all_port_names):
+        (LintTest):
+        (LintTest.test_all_configurations):
+        (LintTest.test_lint_test_files):
+        (LintTest.test_lint_test_files__errors):
+        (MainTest):
+        (MainTest.test_success):
+        (MainTest.test_success.interrupting_lint):
+        (MainTest.test_success.successful_lint):
+        (MainTest.test_success.exception_raising_lint):
+        * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+        (main):
+        * Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py:
+        (StreamTestingMixin.assertNotEmpty):
+
 2012-12-17  Adam Klein  <adamk@chromium.org>
 
         build-webkit: rename --template-tag to --template-element to match ENABLE #define name
diff --git a/Tools/Scripts/lint-test-expectations b/Tools/Scripts/lint-test-expectations
new file mode 100755 (executable)
index 0000000..c56eb77
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+# Copyright (C) 2012 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import sys
+
+from webkitpy.common import version_check
+from webkitpy.layout_tests import lint_test_expectations
+
+
+sys.exit(lint_test_expectations.main(sys.argv[1:], sys.stdout, sys.stderr))
+
diff --git a/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations.py b/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations.py
new file mode 100644 (file)
index 0000000..52aa7b9
--- /dev/null
@@ -0,0 +1,111 @@
+# Copyright (C) 2012 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+import optparse
+import signal
+import traceback
+
+from webkitpy.common.host import Host
+from webkitpy.layout_tests.models import test_expectations
+from webkitpy.layout_tests.port import platform_options
+
+
+# This mirrors what the shell normally does.
+INTERRUPTED_EXIT_STATUS = signal.SIGINT + 128
+
+# This is a randomly chosen exit code that can be tested against to
+# indicate that an unexpected exception occurred.
+EXCEPTIONAL_EXIT_STATUS = 254
+
+_log = logging.getLogger(__name__)
+
+
+def lint(host, options, logging_stream):
+    logger = logging.getLogger()
+    logger.setLevel(logging.INFO)
+    handler = logging.StreamHandler(logging_stream)
+    logger.addHandler(handler)
+
+    try:
+        ports_to_lint = [host.port_factory.get(name) for name in host.port_factory.all_port_names(options.platform)]
+        files_linted = set()
+        lint_failed = False
+
+        for port_to_lint in ports_to_lint:
+            expectations_dict = port_to_lint.expectations_dict()
+
+            # FIXME: This won't work if multiple ports share a TestExpectations file but support different modifiers in the file.
+            for expectations_file in expectations_dict.keys():
+                if expectations_file in files_linted:
+                    continue
+
+                try:
+                    test_expectations.TestExpectations(port_to_lint,
+                        expectations_to_lint={expectations_file: expectations_dict[expectations_file]})
+                except test_expectations.ParseError as e:
+                    lint_failed = True
+                    _log.error('')
+                    for warning in e.warnings:
+                        _log.error(warning)
+                    _log.error('')
+                files_linted.add(expectations_file)
+
+        if lint_failed:
+            _log.error('Lint failed.')
+            return -1
+
+        _log.info('Lint succeeded.')
+        return 0
+    finally:
+        logger.removeHandler(handler)
+
+
+def main(argv, _, stderr):
+    parser = optparse.OptionParser(option_list=platform_options(use_globs=True))
+    options, _ = parser.parse_args(argv)
+
+    if options.platform and 'test' in options.platform:
+        # It's a bit lame to import mocks into real code, but this allows the user
+        # to run tests against the test platform interactively, which is useful for
+        # debugging test failures.
+        from webkitpy.common.host_mock import MockHost
+        host = MockHost()
+    else:
+        host = Host()
+
+    try:
+        exit_status = lint(host, options, stderr)
+    except KeyboardInterrupt:
+        exit_status = INTERRUPTED_EXIT_STATUS
+    except Exception as e:
+        print >> stderr, '\n%s raised: %s' % (e.__class__.__name__, str(e))
+        traceback.print_exc(file=stderr)
+        exit_status = EXCEPTIONAL_EXIT_STATUS
+
+    return exit_status
diff --git a/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations_unittest.py b/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations_unittest.py
new file mode 100644 (file)
index 0000000..32ea8b9
--- /dev/null
@@ -0,0 +1,155 @@
+# Copyright (C) 2012 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import optparse
+import StringIO
+import unittest
+
+from webkitpy.common.host_mock import MockHost
+from webkitpy.layout_tests import lint_test_expectations
+
+
+class FakePort(object):
+    def __init__(self, host, name, path):
+        self.host = host
+        self.name = name
+        self.path = path
+
+    def test_configuration(self):
+        return None
+
+    def expectations_dict(self):
+        self.host.ports_parsed.append(self.name)
+        return {self.path: ''}
+
+    def skipped_layout_tests(self, _):
+        return set([])
+
+    def all_test_configurations(self):
+        return []
+
+    def configuration_specifier_macros(self):
+        return []
+
+    def get_option(self, _, val):
+        return val
+
+
+class FakeFactory(object):
+    def __init__(self, host, ports):
+        self.host = host
+        self.ports = {}
+        for port in ports:
+            self.ports[port.name] = port
+
+    def get(self, port_name, *args, **kwargs):  # pylint: disable=W0613,E0202
+        return self.ports[port_name]
+
+    def all_port_names(self, platform=None):  # pylint: disable=W0613,E0202
+        return sorted(self.ports.keys())
+
+
+class LintTest(unittest.TestCase):
+    def test_all_configurations(self):
+        host = MockHost()
+        host.ports_parsed = []
+        host.port_factory = FakeFactory(host, (FakePort(host, 'a', 'path-to-a'),
+                                               FakePort(host, 'b', 'path-to-b'),
+                                               FakePort(host, 'b-win', 'path-to-b')))
+
+        logging_stream = StringIO.StringIO()
+        options = optparse.Values({'platform': None})
+        res = lint_test_expectations.lint(host, options, logging_stream)
+        self.assertEqual(res, 0)
+        self.assertEqual(host.ports_parsed, ['a', 'b', 'b-win'])
+
+    def test_lint_test_files(self):
+        logging_stream = StringIO.StringIO()
+        options = optparse.Values({'platform': 'test-mac-leopard'})
+        host = MockHost()
+
+        # pylint appears to complain incorrectly about the method overrides pylint: disable=E0202,C0322
+        # FIXME: incorrect complaints about spacing pylint: disable=C0322
+        host.port_factory.all_port_names = lambda platform=None: [platform]
+
+        res = lint_test_expectations.lint(host, options, logging_stream)
+
+        self.assertEqual(res, 0)
+        self.assertTrue('Lint succeeded' in logging_stream.getvalue())
+
+    def test_lint_test_files__errors(self):
+        options = optparse.Values({'platform': 'test', 'debug_rwt_logging': False})
+        host = MockHost()
+
+        # FIXME: incorrect complaints about spacing pylint: disable=C0322
+        port = host.port_factory.get(options.platform, options=options)
+        port.expectations_dict = lambda: {'foo': '-- syntax error1', 'bar': '-- syntax error2'}
+
+        host.port_factory.get = lambda platform, options=None: port
+        host.port_factory.all_port_names = lambda platform=None: [port.name()]
+
+        logging_stream = StringIO.StringIO()
+
+        res = lint_test_expectations.lint(host, options, logging_stream)
+
+        self.assertEqual(res, -1)
+        self.assertTrue('Lint failed' in logging_stream.getvalue())
+        self.assertTrue('foo:1' in logging_stream.getvalue())
+        self.assertTrue('bar:1' in logging_stream.getvalue())
+
+
+class MainTest(unittest.TestCase):
+    def test_success(self):
+        orig_lint_fn = lint_test_expectations.lint
+
+        # unused args pylint: disable=W0613
+        def interrupting_lint(host, options, logging_stream):
+            raise KeyboardInterrupt
+
+        def successful_lint(host, options, logging_stream):
+            return 0
+
+        def exception_raising_lint(host, options, logging_stream):
+            assert False
+
+        stdout = StringIO.StringIO()
+        stderr = StringIO.StringIO()
+        try:
+            lint_test_expectations.lint = interrupting_lint
+            res = lint_test_expectations.main([], stdout, stderr)
+            self.assertEqual(res, lint_test_expectations.INTERRUPTED_EXIT_STATUS)
+
+            lint_test_expectations.lint = successful_lint
+            res = lint_test_expectations.main(['--platform', 'test'], stdout, stderr)
+            self.assertEqual(res, 0)
+
+            lint_test_expectations.lint = exception_raising_lint
+            res = lint_test_expectations.main([], stdout, stderr)
+            self.assertEqual(res, lint_test_expectations.EXCEPTIONAL_EXIT_STATUS)
+        finally:
+            lint_test_expectations.lint = orig_lint_fn
index 4a13054..fcfd02e 100644 (file)
@@ -54,46 +54,6 @@ INTERRUPTED_EXIT_STATUS = signal.SIGINT + 128
 EXCEPTIONAL_EXIT_STATUS = 254
 
 
-def lint(port, options, logging_stream):
-    host = port.host
-    logging.getLogger().setLevel(logging.DEBUG if options.debug_rwt_logging else logging.INFO)
-    printer = printing.Printer(port, options, logging_stream, logger=logging.getLogger())
-
-    if options.platform:
-        ports_to_lint = [port]
-    else:
-        ports_to_lint = [host.port_factory.get(name) for name in host.port_factory.all_port_names()]
-
-    files_linted = set()
-    lint_failed = False
-
-    for port_to_lint in ports_to_lint:
-        expectations_dict = port_to_lint.expectations_dict()
-
-        # FIXME: This won't work if multiple ports share a TestExpectations file but support different modifiers in the file.
-        for expectations_file in expectations_dict.keys():
-            if expectations_file in files_linted:
-                continue
-
-            try:
-                test_expectations.TestExpectations(port_to_lint, expectations_to_lint={expectations_file: expectations_dict[expectations_file]})
-            except test_expectations.ParseError, e:
-                lint_failed = True
-                _log.error('')
-                for warning in e.warnings:
-                    _log.error(warning)
-                _log.error('')
-            files_linted.add(expectations_file)
-
-    if lint_failed:
-        _log.error('Lint failed.')
-        printer.cleanup()
-        return -1
-    _log.info('Lint succeeded.')
-    printer.cleanup()
-    return 0
-
-
 def run(port, options, args, logging_stream):
     try:
         printer = printing.Printer(port, options, logging_stream, logger=logging.getLogger())
@@ -401,7 +361,8 @@ def main(argv=None, stdout=sys.stdout, stderr=sys.stderr):
     logging.getLogger().setLevel(logging.DEBUG if options.debug_rwt_logging else logging.INFO)
 
     if options.lint_test_files:
-        return lint(port, options, stderr)
+        from webkitpy.layout_tests.lint_test_expectations import lint
+        return lint(host, options, stderr)
 
     try:
         run_details = run(port, options, args, stderr)
index f373d3b..be15df8 100644 (file)
@@ -169,95 +169,6 @@ class StreamTestingMixin(object):
         self.assertTrue(stream.getvalue())
 
 
-class LintTest(unittest.TestCase, StreamTestingMixin):
-    def test_all_configurations(self):
-
-        class FakePort(object):
-            def __init__(self, host, name, path):
-                self.host = host
-                self.name = name
-                self.path = path
-
-            def test_configuration(self):
-                return None
-
-            def expectations_dict(self):
-                self.host.ports_parsed.append(self.name)
-                return {self.path: ''}
-
-            def skipped_layout_tests(self, tests):
-                return set([])
-
-            def all_test_configurations(self):
-                return []
-
-            def configuration_specifier_macros(self):
-                return []
-
-            def path_from_webkit_base(self):
-                return ''
-
-            def get_option(self, name, val):
-                return val
-
-        class FakeFactory(object):
-            def __init__(self, host, ports):
-                self.host = host
-                self.ports = {}
-                for port in ports:
-                    self.ports[port.name] = port
-
-            def get(self, port_name, *args, **kwargs):
-                return self.ports[port_name]
-
-            def all_port_names(self):
-                return sorted(self.ports.keys())
-
-        host = MockHost()
-        host.ports_parsed = []
-        host.port_factory = FakeFactory(host, (FakePort(host, 'a', 'path-to-a'),
-                                               FakePort(host, 'b', 'path-to-b'),
-                                               FakePort(host, 'b-win', 'path-to-b')))
-
-        logging_stream = StringIO.StringIO()
-        self.assertEqual(run_webkit_tests.lint(host.port_factory.ports['a'], MockOptions(platform=None, debug_rwt_logging=False), logging_stream), 0)
-        self.assertEqual(host.ports_parsed, ['a', 'b', 'b-win'])
-
-        host.ports_parsed = []
-        self.assertEqual(run_webkit_tests.lint(host.port_factory.ports['a'], MockOptions(platform='a', debug_rwt_logging=False), logging_stream), 0)
-        self.assertEqual(host.ports_parsed, ['a'])
-
-    def test_lint_test_files(self):
-        logging_stream = StringIO.StringIO()
-        options, _ = parse_args(['--platform', 'test', '--lint-test-files'])
-        host = MockHost()
-        port_obj = host.port_factory.get(options.platform, options=options)
-        res = run_webkit_tests.lint(port_obj, options, logging_stream)
-        self.assertEqual(res, 0)
-        self.assertTrue('Lint succeeded' in logging_stream.getvalue())
-
-    def test_lint_test_files__errors(self):
-        options, _ = parse_args(['--platform', 'test', '--lint-test-files'])
-        host = MockHost()
-        port_obj = host.port_factory.get(options.platform, options=options)
-        port_obj.expectations_dict = lambda: {'': '-- syntax error'}
-
-        logging_stream = StringIO.StringIO()
-        res = run_webkit_tests.lint(port_obj, options, logging_stream)
-
-        self.assertEqual(res, -1)
-        self.assertTrue('Lint failed' in logging_stream.getvalue())
-
-        # ensure we lint *all* of the files in the cascade.
-        port_obj.expectations_dict = lambda: {'foo': '-- syntax error1', 'bar': '-- syntax error2'}
-        logging_stream = StringIO.StringIO()
-        res = run_webkit_tests.lint(port_obj, options, logging_stream)
-
-        self.assertEqual(res, -1)
-        self.assertTrue('foo:1' in logging_stream.getvalue())
-        self.assertTrue('bar:1' in logging_stream.getvalue())
-
-
 class MainTest(unittest.TestCase, StreamTestingMixin):
     def setUp(self):
         # A real PlatformInfo object is used here instead of a