Changeset 112437 in webkit


Ignore:
Timestamp:
Mar 28, 2012 1:59:06 PM (12 years ago)
Author:
dpranke@chromium.org
Message:

test-webkitpy should support files, directories, and packages as command line args
https://bugs.webkit.org/show_bug.cgi?id=76765

Reviewed by Adam Barth.

This patch adds support for specifying files, directories, and
packages to test-webkitpy along with the already existing
support for modules, test classes, and individual test names.

Also, fix a bug in filesystem_mock where we wouldn't normalize a
path containing a reference to the current directory properly,
for example, '/foo/./bar.py'.

  • Scripts/webkitpy/common/system/filesystem_mock.py:

(MockFileSystem.normpath):

  • Scripts/webkitpy/test/main.py:

(Tester._configure_logging):
(Tester._run_tests):

  • Scripts/webkitpy/test/test_finder.py:

(TestDirectoryTree.find_modules):
(TestDirectoryTree.subpath):
(TestFinder.is_dotted_name):
(TestFinder.find_names):
(TestFinder):
(TestFinder._find_names_for_arg):
(TestFinder._find_in_trees):
(TestFinder._default_names):

  • Scripts/webkitpy/test/test_finder_unittest.py:

(TestFinderTest.setUp):
(TestFinderTest.tearDown):
(TestFinderTest.check_names):
(TestFinderTest.test_default_names):
(TestFinderTest):
(TestFinderTest.test_paths):

Location:
trunk/Tools
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r112435 r112437  
     12012-03-28  Dirk Pranke  <dpranke@chromium.org>
     2
     3        test-webkitpy should support files, directories, and packages as command line args
     4        https://bugs.webkit.org/show_bug.cgi?id=76765
     5
     6        Reviewed by Adam Barth.
     7
     8        This patch adds support for specifying files, directories, and
     9        packages to test-webkitpy along with the already existing
     10        support for modules, test classes, and individual test names.
     11
     12        Also, fix a bug in filesystem_mock where we wouldn't normalize a
     13        path containing a reference to the current directory properly,
     14        for example, '/foo/./bar.py'.
     15
     16        * Scripts/webkitpy/common/system/filesystem_mock.py:
     17        (MockFileSystem.normpath):
     18        * Scripts/webkitpy/test/main.py:
     19        (Tester._configure_logging):
     20        (Tester._run_tests):
     21        * Scripts/webkitpy/test/test_finder.py:
     22        (TestDirectoryTree.find_modules):
     23        (TestDirectoryTree.subpath):
     24        (TestFinder.is_dotted_name):
     25        (TestFinder.find_names):
     26        (TestFinder):
     27        (TestFinder._find_names_for_arg):
     28        (TestFinder._find_in_trees):
     29        (TestFinder._default_names):
     30        * Scripts/webkitpy/test/test_finder_unittest.py:
     31        (TestFinderTest.setUp):
     32        (TestFinderTest.tearDown):
     33        (TestFinderTest.check_names):
     34        (TestFinderTest.test_default_names):
     35        (TestFinderTest):
     36        (TestFinderTest.test_paths):
     37
    1382012-03-28  Simon Fraser  <simon.fraser@apple.com>
    239
  • trunk/Tools/Scripts/webkitpy/common/system/filesystem_mock.py

    r112168 r112437  
    279279        # This function is called a lot, so we try to optimize the common cases
    280280        # instead of always calling _slow_but_correct_normpath(), above.
    281         if '..' in path:
     281        if '..' in path or '/./' in path:
    282282            # This doesn't happen very often; don't bother trying to optimize it.
    283283            return self._slow_but_correct_normpath(path)
  • trunk/Tools/Scripts/webkitpy/test/main.py

    r112298 r112437  
    2525import logging
    2626import optparse
    27 import os
    2827import StringIO
    2928import sys
     
    103102        # interfere with modifications made by other modules (e.g. in unit
    104103        # tests).
     104        handler.name = __name__
    105105        handler.setLevel(log_level)
    106106        formatter = logging.Formatter("%(message)s")
  • trunk/Tools/Scripts/webkitpy/test/test_finder.py

    r112168 r112437  
    2525
    2626import logging
     27import re
    2728import sys
    2829
     
    4142            self.search_directory = filesystem.join(self.top_directory, starting_subdirectory)
    4243
    43     def find_modules(self, suffixes):
     44    def find_modules(self, suffixes, sub_directory=None):
     45        if sub_directory:
     46            search_directory = self.filesystem.join(self.top_directory, sub_directory)
     47        else:
     48            search_directory = self.search_directory
    4449
    4550        def file_filter(filesystem, dirname, basename):
    4651            return any(basename.endswith(suffix) for suffix in suffixes)
    4752
    48         filenames = self.filesystem.files_under(self.search_directory, file_filter=file_filter)
     53        filenames = self.filesystem.files_under(search_directory, file_filter=file_filter)
    4954        return [self.to_module(filename) for filename in filenames]
    5055
    5156    def to_module(self, path):
    5257        return path.replace(self.top_directory + self.filesystem.sep, '').replace(self.filesystem.sep, '.')[:-3]
     58
     59    def subpath(self, path):
     60        """Returns the relative path from the top of the tree to the path, or None if the path is not under the top of the tree."""
     61        realpath = self.filesystem.realpath(self.filesystem.join(self.top_directory, path))
     62        if realpath.startswith(self.top_directory + self.filesystem.sep):
     63            return realpath.replace(self.top_directory + self.filesystem.sep, '')
     64        return None
     65
    5366
    5467    def clean(self):
     
    8194        return any(self.filesystem.exists(self.filesystem.join(tree.top_directory, relpath)) for tree in self.trees)
    8295
     96    def is_dotted_name(self, name):
     97        return re.match(r'[a-zA-Z.][a-zA-Z0-9_.]*', name)
     98
    8399    def to_module(self, path):
    84100        for tree in self.trees:
     
    88104
    89105    def find_names(self, args, skip_integrationtests, find_all):
    90         if args:
    91             return args
    92 
    93106        suffixes = ['_unittest.py']
    94107        if not skip_integrationtests:
    95108            suffixes.append('_integrationtest.py')
    96109
     110        if args:
     111            names = []
     112            for arg in args:
     113                names.extend(self._find_names_for_arg(arg, suffixes))
     114            return names
     115
     116        return self._default_names(suffixes, find_all)
     117
     118    def _find_names_for_arg(self, arg, suffixes):
     119        realpath = self.filesystem.realpath(arg)
     120        if self.filesystem.exists(realpath):
     121            names = self._find_in_trees(realpath, suffixes)
     122            if not names:
     123                _log.error("%s is not in one of the test trees." % arg)
     124            return names
     125
     126        # See if it's a python package in a tree (or a relative path from the top of a tree).
     127        names = self._find_in_trees(arg.replace('.', self.filesystem.sep), suffixes)
     128        if names:
     129            return names
     130
     131        if self.is_dotted_name(arg):
     132            # The name may not exist, but that's okay; we'll find out later.
     133            return [arg]
     134
     135        _log.error("%s is not a python name or an existing file or directory." % arg)
     136        return []
     137
     138    def _find_in_trees(self, path, suffixes):
     139        for tree in self.trees:
     140            relpath = tree.subpath(path)
     141            if not relpath:
     142                continue
     143            if self.filesystem.isfile(path):
     144                return [tree.to_module(path)]
     145            else:
     146                return tree.find_modules(suffixes, path)
     147        return []
     148
     149    def _default_names(self, suffixes, find_all):
    97150        modules = []
    98151        for tree in self.trees:
  • trunk/Tools/Scripts/webkitpy/test/test_finder_unittest.py

    r112168 r112437  
    2525
    2626from webkitpy.common.system.filesystem_mock import MockFileSystem
     27from webkitpy.common.system.outputcapture import OutputCapture
    2728from webkitpy.test.test_finder import TestFinder
    2829
     
    3738          '/foo2/bar2/baz2_integrationtest.py': '',
    3839          '/foo2/bar2/missing.pyc': '',
     40          '/tmp/another_unittest.py': '',
    3941        }
    4042        self.fs = MockFileSystem(files)
     
    4244        self.finder.add_tree('/foo', 'bar')
    4345        self.finder.add_tree('/foo2')
     46
     47        # Here we have to jump through a hoop to make sure test-webkitpy doesn't log
     48        # any messages from these tests :(.
    4449        self.root_logger = logging.getLogger()
    45         self.log_level = self.root_logger.level
    46         self.root_logger.setLevel(logging.WARNING)
     50        self.log_handler = None
     51        for h in self.root_logger.handlers:
     52            if getattr(h, 'name', None) == 'webkitpy.test.main':
     53                self.log_handler = h
     54                break
     55        if self.log_handler:
     56            self.log_level = self.log_handler.level
     57            self.log_handler.level = logging.CRITICAL
    4758
    4859    def tearDown(self):
    49         self.root_logger.setLevel(self.log_level)
     60        if self.log_handler:
     61            self.log_handler.setLevel(self.log_level)
    5062
    5163    def test_additional_system_paths(self):
     
    7183        self.assertFalse(self.fs.exists('/foo2/bar2/missing.pyc'))
    7284
    73     def test_find_names(self):
    74         self.assertEquals(self.finder.find_names([], skip_integrationtests=False, find_all=True),
    75             ['bar.baz_unittest', 'bar2.baz2_integrationtest'])
     85    def check_names(self, names, expected_names, skip_integrationtests=False, find_all=False):
     86        self.assertEquals(self.finder.find_names(names, skip_integrationtests, find_all),
     87                          expected_names)
    7688
    77         self.assertEquals(self.finder.find_names([], skip_integrationtests=True, find_all=True),
    78             ['bar.baz_unittest'])
    79         self.assertEquals(self.finder.find_names([], skip_integrationtests=True, find_all=False),
    80             ['bar.baz_unittest'])
     89    def test_default_names(self):
     90        self.check_names([], ['bar.baz_unittest', 'bar2.baz2_integrationtest'])
     91        self.check_names([], ['bar.baz_unittest'], skip_integrationtests=True, find_all=True)
     92        self.check_names([], ['bar.baz_unittest'], skip_integrationtests=True, find_all=False)
    8193
    8294        # Should return the names given it, even if they don't exist.
    83         self.assertEquals(self.finder.find_names(['foobar'], skip_integrationtests=True, find_all=True),
    84             ['foobar'])
     95        self.check_names(['foobar'], ['foobar'], skip_integrationtests=True, find_all=False)
    8596
     97    def test_paths(self):
     98        self.fs.chdir('/foo/bar')
     99        self.check_names(['baz_unittest.py'], ['bar.baz_unittest'])
     100        self.check_names(['./baz_unittest.py'], ['bar.baz_unittest'])
     101        self.check_names(['/foo/bar/baz_unittest.py'], ['bar.baz_unittest'])
     102        self.check_names(['.'], ['bar.baz_unittest'])
     103        self.check_names(['../../foo2/bar2'], ['bar2.baz2_integrationtest'])
     104
     105        self.fs.chdir('/')
     106        self.check_names(['bar'], ['bar.baz_unittest'])
     107        self.check_names(['/foo/bar/'], ['bar.baz_unittest'])
     108
     109        # This works 'by accident' since it maps onto a package.
     110        self.check_names(['bar/'], ['bar.baz_unittest'])
     111
     112        # This should log an error, since it's outside the trees.
     113        oc = OutputCapture()
     114        oc.set_log_level(logging.ERROR)
     115        oc.capture_output()
     116        try:
     117            self.check_names(['/tmp/another_unittest.py'], [])
     118        finally:
     119            _, _, logs = oc.restore_output()
     120            self.assertTrue('another_unittest.py' in logs)
     121
     122        # Paths that don't exist are errors.
     123        oc.capture_output()
     124        try:
     125            self.check_names(['/foo/bar/notexist_unittest.py'], [])
     126        finally:
     127            _, _, logs = oc.restore_output()
     128            self.assertTrue('notexist_unittest.py' in logs)
     129
     130        # Names that don't exist are caught later, at load time.
     131        self.check_names(['bar.notexist_unittest'], ['bar.notexist_unittest'])
    86132
    87133if __name__ == '__main__':
Note: See TracChangeset for help on using the changeset viewer.