111f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org#!/usr/bin/python 211f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org 311f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org""" 411f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.orgCopyright 2014 Google Inc. 511f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org 611f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.orgUse of this source code is governed by a BSD-style license that can be 711f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.orgfound in the LICENSE file. 811f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org 911f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.orgA wrapper around the standard Python unittest library, adding features we need 1011f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.orgfor various unittests within this directory. 1166ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger 1266ed8dc4bfd63e4552a213cb17909f9fbbf59abdepogerTODO(epoger): Move this into the common repo for broader use? Or at least in 1366ed8dc4bfd63e4552a213cb17909f9fbbf59abdepogera more common place within the Skia repo? 1411f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org""" 1511f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org 163f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.orgimport errno 1766ed8dc4bfd63e4552a213cb17909f9fbbf59abdepogerimport filecmp 1811f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.orgimport os 193f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.orgimport shutil 2066ed8dc4bfd63e4552a213cb17909f9fbbf59abdepogerimport tempfile 2111f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.orgimport unittest 2211f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org 2366ed8dc4bfd63e4552a213cb17909f9fbbf59abdepogerTRUNK_DIR = os.path.abspath(os.path.join( 2466ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger os.path.dirname(__file__), os.pardir, os.pardir)) 25164052e9cef7b1b6d64860f52176a4413b23fc5ccommit-bot@chromium.org 2611f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org 2711f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.orgclass TestCase(unittest.TestCase): 2811f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org 2966ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger def __init__(self, *args, **kwargs): 3066ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger super(TestCase, self).__init__(*args, **kwargs) 3166ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger # Subclasses should override this default value if they want their output 3266ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger # to be automatically compared against expectations (see setUp and tearDown) 3366ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger self._testdata_dir = None 3466ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger 3566ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger def setUp(self): 3666ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger """Called before each test.""" 3766ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger # Get the name of this test, in such a way that it will be consistent 3866ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger # regardless of the directory it is run from (throw away package names, 3966ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger # if any). 4066ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger self._test_name = '.'.join(self.id().split('.')[-3:]) 4166ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger 4266ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger self._temp_dir = tempfile.mkdtemp() 4366ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger if self._testdata_dir: 4466ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger self.create_empty_dir(self.output_dir_actual) 4566ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger 4666ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger def tearDown(self): 4766ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger """Called after each test.""" 4866ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger shutil.rmtree(self._temp_dir) 4966ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger if self._testdata_dir and os.path.exists(self.output_dir_expected): 5066ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger different_files = _find_different_files(self.output_dir_actual, 5166ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger self.output_dir_expected) 5266ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger # Don't add any cleanup code below this assert! 5366ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger # Then if tests fail, the artifacts will not be cleaned up. 5466ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger assert (not different_files), \ 5566ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger ('found differing files:\n' + 5666ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger '\n'.join(['tkdiff %s %s &' % ( 5766ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger os.path.join(self.output_dir_actual, basename), 5866ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger os.path.join(self.output_dir_expected, basename)) 5966ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger for basename in different_files])) 6066ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger 6166ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger @property 6266ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger def temp_dir(self): 6366ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger return self._temp_dir 6466ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger 6566ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger @property 6666ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger def input_dir(self): 6766ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger assert self._testdata_dir, 'self._testdata_dir must be set' 6866ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger return os.path.join(self._testdata_dir, 'inputs') 6966ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger 7066ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger @property 7166ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger def output_dir_actual(self): 7266ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger assert self._testdata_dir, 'self._testdata_dir must be set' 7366ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger return os.path.join( 7466ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger self._testdata_dir, 'outputs', 'actual', self._test_name) 7566ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger 7666ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger @property 7766ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger def output_dir_expected(self): 7866ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger assert self._testdata_dir, 'self._testdata_dir must be set' 7966ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger return os.path.join( 8066ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger self._testdata_dir, 'outputs', 'expected', self._test_name) 8166ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger 8211f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org def shortDescription(self): 8311f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org """Tell unittest framework to not print docstrings for test cases.""" 8411f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org return None 8511f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org 863f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org def create_empty_dir(self, path): 873f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org """Creates an empty directory at path and returns path. 883f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org 893f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org Args: 903f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org path: path on local disk 913f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org """ 9266ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger # Delete the old one, if any. 9366ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger if os.path.isdir(path): 9466ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger shutil.rmtree(path=path, ignore_errors=True) 9566ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger elif os.path.lexists(path): 9666ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger os.remove(path) 9766ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger 9866ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger # Create the new one. 993f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org try: 1003f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org os.makedirs(path) 1013f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org except OSError as exc: 10266ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger # Guard against race condition (somebody else is creating the same dir) 1033f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org if exc.errno != errno.EEXIST: 1043f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org raise 1053f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org return path 1063f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org 10711f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org 10866ed8dc4bfd63e4552a213cb17909f9fbbf59abdepogerdef _find_different_files(dir1, dir2, ignore_subtree_names=None): 10966ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger """Returns a list of any files that differ between the directory trees rooted 11066ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger at dir1 and dir2. 11111f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org 11266ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger Args: 11366ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger dir1: root of a directory tree; if nonexistent, will raise OSError 11466ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger dir2: root of another directory tree; if nonexistent, will raise OSError 11566ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger ignore_subtree_names: list of subtree directory names to ignore; 11666ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger defaults to ['.svn'], so all SVN files are ignores 11711f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org 11866ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger TODO(epoger): include the dirname within each filename (not just the 11966ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger basename), to make it easier to locate any differences 12066ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger """ 12166ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger differing_files = [] 12266ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger if ignore_subtree_names is None: 12366ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger ignore_subtree_names = ['.svn'] 12466ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger dircmp = filecmp.dircmp(dir1, dir2, ignore=ignore_subtree_names) 12566ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger differing_files.extend(dircmp.left_only) 12666ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger differing_files.extend(dircmp.right_only) 12766ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger differing_files.extend(dircmp.common_funny) 12866ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger differing_files.extend(dircmp.diff_files) 12966ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger differing_files.extend(dircmp.funny_files) 13066ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger for common_dir in dircmp.common_dirs: 13166ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger differing_files.extend(_find_different_files( 13266ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger os.path.join(dir1, common_dir), os.path.join(dir2, common_dir))) 13366ed8dc4bfd63e4552a213cb17909f9fbbf59abdepoger return differing_files 13411f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org 13511f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org 13611f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.orgdef main(test_case_class): 13711f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org """Run the unit tests within the given class. 13811f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org 13911f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org Raises an Exception if any of those tests fail (in case we are running in the 14011f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org context of run_all.py, which depends on that Exception to signal failures). 14111f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org """ 14211f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org suite = unittest.TestLoader().loadTestsFromTestCase(test_case_class) 14311f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org results = unittest.TextTestRunner(verbosity=2).run(suite) 14411f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org if not results.wasSuccessful(): 14511f156201abe0d5e30f25a60bce1f4ae547c4083commit-bot@chromium.org raise Exception('failed unittest %s' % test_case_class) 146