1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
#!/usr/bin/python
"""
Copyright 2014 Google Inc.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
A wrapper around the standard Python unittest library, adding features we need
for various unittests within this directory.
TODO(epoger): Move this into the common repo for broader use? Or at least in
a more common place within the Skia repo?
"""
import errno
import filecmp
import os
import shutil
import tempfile
import unittest
TRUNK_DIR = os.path.abspath(os.path.join(
os.path.dirname(__file__), os.pardir, os.pardir))
class TestCase(unittest.TestCase):
def __init__(self, *args, **kwargs):
super(TestCase, self).__init__(*args, **kwargs)
# Subclasses should override this default value if they want their output
# to be automatically compared against expectations (see setUp and tearDown)
self._testdata_dir = None
def setUp(self):
"""Called before each test."""
# Get the name of this test, in such a way that it will be consistent
# regardless of the directory it is run from (throw away package names,
# if any).
self._test_name = '.'.join(self.id().split('.')[-3:])
self._temp_dir = tempfile.mkdtemp()
if self._testdata_dir:
self.create_empty_dir(self.output_dir_actual)
def tearDown(self):
"""Called after each test."""
shutil.rmtree(self._temp_dir)
if self._testdata_dir and os.path.exists(self.output_dir_expected):
different_files = _find_different_files(self.output_dir_actual,
self.output_dir_expected)
# Don't add any cleanup code below this assert!
# Then if tests fail, the artifacts will not be cleaned up.
assert (not different_files), \
('found differing files:\n' +
'\n'.join(['tkdiff %s %s &' % (
os.path.join(self.output_dir_actual, basename),
os.path.join(self.output_dir_expected, basename))
for basename in different_files]))
@property
def temp_dir(self):
return self._temp_dir
@property
def input_dir(self):
assert self._testdata_dir, 'self._testdata_dir must be set'
return os.path.join(self._testdata_dir, 'inputs')
@property
def output_dir_actual(self):
assert self._testdata_dir, 'self._testdata_dir must be set'
return os.path.join(
self._testdata_dir, 'outputs', 'actual', self._test_name)
@property
def output_dir_expected(self):
assert self._testdata_dir, 'self._testdata_dir must be set'
return os.path.join(
self._testdata_dir, 'outputs', 'expected', self._test_name)
def shortDescription(self):
"""Tell unittest framework to not print docstrings for test cases."""
return None
def create_empty_dir(self, path):
"""Creates an empty directory at path and returns path.
Args:
path: path on local disk
"""
# Delete the old one, if any.
if os.path.isdir(path):
shutil.rmtree(path=path, ignore_errors=True)
elif os.path.lexists(path):
os.remove(path)
# Create the new one.
try:
os.makedirs(path)
except OSError as exc:
# Guard against race condition (somebody else is creating the same dir)
if exc.errno != errno.EEXIST:
raise
return path
def _find_different_files(dir1, dir2, ignore_subtree_names=None):
"""Returns a list of any files that differ between the directory trees rooted
at dir1 and dir2.
Args:
dir1: root of a directory tree; if nonexistent, will raise OSError
dir2: root of another directory tree; if nonexistent, will raise OSError
ignore_subtree_names: list of subtree directory names to ignore;
defaults to ['.svn'], so all SVN files are ignores
TODO(epoger): include the dirname within each filename (not just the
basename), to make it easier to locate any differences
"""
differing_files = []
if ignore_subtree_names is None:
ignore_subtree_names = ['.svn']
dircmp = filecmp.dircmp(dir1, dir2, ignore=ignore_subtree_names)
differing_files.extend(dircmp.left_only)
differing_files.extend(dircmp.right_only)
differing_files.extend(dircmp.common_funny)
differing_files.extend(dircmp.diff_files)
differing_files.extend(dircmp.funny_files)
for common_dir in dircmp.common_dirs:
differing_files.extend(_find_different_files(
os.path.join(dir1, common_dir), os.path.join(dir2, common_dir)))
return differing_files
def main(test_case_class):
"""Run the unit tests within the given class.
Raises an Exception if any of those tests fail (in case we are running in the
context of run_all.py, which depends on that Exception to signal failures).
"""
suite = unittest.TestLoader().loadTestsFromTestCase(test_case_class)
results = unittest.TextTestRunner(verbosity=2).run(suite)
if not results.wasSuccessful():
raise Exception('failed unittest %s' % test_case_class)
|