Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Side by Side Diff: media/tools/layout_tests/layouttests.py

Issue 7693018: Intial checkin of layout test analyzer. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Minor modification after doublecheck. Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 #!/usr/bin/python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Layout tests module that is necessary for tha layout analyzer.
7
8 Layout tests are stored in Webkit SVN and LayoutTestCaseManager collects these
9 layout test cases (including description).
10 """
11
12 import copy
13 import csv
14 import locale
15 import pysvn
16 import re
17 import sys
18 import urllib2
19
20
21 # Webkit SVN root location.
22 DEFAULT_LAYOUTTEST_LOCATION = (
23 'http://svn.webkit.org/repository/webkit/trunk/LayoutTests/')
24
25 # When parsing the test HTML file and finding the test description,
26 # this script tries to find the test description using sentences
27 # starting with these keywords. This is adhoc but it is the only way
28 # since there is no standard for writing test description.
29 KEYWORDS_FOR_TEST_DESCRIPTION = ['This test', 'Tests that', 'Test ']
30
31 # If cannot find the keywords, this script tries to find test case
32 # description by the following tags.
33 TAGS_FOR_TEST_DESCRIPTION = ['title', 'p', 'div']
34
35 # If cannot find the tags, this script tries to find the test case
36 # description in the sentence containing following words.
37 KEYWORD_FOR_TEST_DESCRIPTION_FAIL_SAFE = ['PASSED ', 'PASS:']
38
39
40 class LayoutTests(object):
41 """A class to store test names in layout tests.
42
43 The test names (including regular expression patterns) are read from a CSV
44 file and used for getting layout test names from Webkit SVN.
45 """
46
47 def __init__(self, layouttest_root_path=DEFAULT_LAYOUTTEST_LOCATION,
48 csv_file_path=None):
49 """Initialize LayoutTests using root and CSV file.
50
51 Args:
52 layouttest_root_path: A location string where Webkit layout tests are
53 stored.
54 csv_file_path: CSV file path. The file contains a list of test names
55 in CSV format. When this parameter is not specified, the names of
56 all layout tests are retrieved under the root directory.
57 """
58 filter_names = []
59 if csv_file_path:
60 filter_names = LayoutTests.GetLayoutTestNamesFromCSV(csv_file_path)
61 parent_location_list = LayoutTests.GetParentDirectoryList(filter_names)
62 if layouttest_root_path.startswith('http://'):
63 name_map = self.GetLayoutTestNamesFromSVN(parent_location_list,
64 layouttest_root_path)
65 else:
66 # TODO(imasaki): support other forms such as CSV for reading test names.
67 pass
68 self.name_map = copy.copy(name_map)
69 # Filter names.
70 for lt_name in name_map.keys():
71 match = False
72 for filter_name in filter_names:
73 if re.search(filter_name, lt_name):
74 match = True
75 break
76 if not match:
77 del self.name_map[lt_name]
78 # We get description only for the filtered names.
79 for lt_name in self.name_map.keys():
80 self.name_map[lt_name] = LayoutTests.GetTestDescriptionFromSVN(lt_name)
81
82 @staticmethod
83 def ExtractTestDescription(txt):
84 """Extract the description description from test code in HTML.
85
86 Currently, we have 4 rules described in the code below.
87 (This example falls into rule 1):
88 <p>
89 This tests the intrinsic size of a video element is the default
90 300,150 before metadata is loaded, and 0,0 after
91 metadata is loaded for an audio-only file.
92 </p>
93 The strategy is very adhoc since the original test case files
94 (in HTML format) do not have standard way to store test description.
95
96 Args:
97 txt: A HTML text which may or may not contain test description.
98
99 Returns:
100 A string that contains test description. Returns 'UNKNOWN' if the
101 test description is not found.
102 """
103 # (1) Try to find test description that contains keywords such as
104 # 'test that' and surrounded by p tag.
105 # This is the most common case.
106 for keyword in KEYWORDS_FOR_TEST_DESCRIPTION:
107 # Try to find <p> and </p>.
108 pattern = r'<p>(.*' + keyword + '.*)</p>'
109 matches = re.search(pattern, txt)
110 if matches is not None:
111 return matches.group(1).strip()
112
113 # (2) Try to find it by using more generic keywords such as 'PASS' etc.
114 for keyword in KEYWORD_FOR_TEST_DESCRIPTION_FAIL_SAFE:
115 # Try to find new lines.
116 pattern = r'\n(.*' + keyword + '.*)\n'
117 matches = re.search(pattern, txt)
118 if matches is not None:
119 # Remove 'p' tag.
120 text = matches.group(1).strip()
121 return text.replace('<p>', '').replace('</p>', '')
122
123 # (3) Try to find it by using HTML tag such as title.
124 for tag in TAGS_FOR_TEST_DESCRIPTION:
125 pattern = r'<' + tag + '>(.*)</' + tag + '>'
126 matches = re.search(pattern, txt)
127 if matches is not None:
128 return matches.group(1).strip()
129
130 # (4) Try to find it by using test description and remove 'p' tag.
131 for keyword in KEYWORDS_FOR_TEST_DESCRIPTION:
132 # Try to find <p> and </p>.
133 pattern = r'\n(.*' + keyword + '.*)\n'
134 matches = re.search(pattern, txt)
135 if matches is not None:
136 # Remove 'p' tag.
137 text = matches.group(1).strip()
138 return text.replace('<p>', '').replace('</p>', '')
139
140 # (5) cannot find test description using existing rules.
141 return 'UNKNOWN'
142
143 @staticmethod
144 def GetLayoutTestNamesFromSVN(parent_location_list,
145 layouttest_root_path):
146 """Get LayoutTest names from Webkit SVN.
147
148 Args:
149 parent_location_list: a list of locations of parent directory. This is
dennis_jeffrey 2011/08/26 19:01:26 nit: 'directory' --> 'directories'
imasaki1 2011/08/26 22:28:44 Done.
150 used when getting layout tests using PySVN.list().
151 layouttest_root_path: the root path of the Webkit SVN directory.
152
153 Returns:
154 a map containing test names as keys for de-dupe.
155 """
156 client = pysvn.Client()
157 # Get directory structure in the Webkit SVN.
158 if parent_location_list is None:
159 # Try to get all the layout tests by enabling recursion option.
160 parent_location_list = ['/\S+\.html$']
161 recursion = True
162 else:
163 recursion = False
164 name_map = {}
165 for parent_location in parent_location_list:
166 if parent_location.endswith('/'):
167 file_list = client.list(layouttest_root_path + parent_location,
168 recurse=recursion)
169 for file_name in file_list:
170 if sys.stdout.isatty():
171 default_encoding = sys.stdout.encoding
172 else:
173 default_encoding = locale.getpreferredencoding()
174 file_name = file_name[0].repos_path.encode(default_encoding)
175 # Remove the word '/truck/LayoutTests'.
176 file_name = file_name.replace('/trunk/LayoutTests/', '')
177 if file_name.endswith('.html'):
178 name_map[file_name] = True
179 return name_map
180
181 @staticmethod
182 def GetLayoutTestNamesFromCSV(csv_file_path):
183 """Get layout test names from CSV file.
184
185 Args:
186 csv_file_path: the path for the CSV file containing test names (including
187 regular expression patterns). The CSV file content has one column and
188 each row contains a test name.
189 """
190 file_object = file(csv_file_path, 'r')
191 reader = csv.reader(file_object)
192 names = [row[0] for row in reader]
193 file_object.close()
194 return names
195
196 @staticmethod
197 def GetParentDirectoryList(names):
198 """Get parent directory list from test names.
199
200 Args:
201 names: a list of test names. The test names also have path information as
202 well (e.g., media/video-zoom.html).
203 """
204 pd_map = {}
205 for name in names:
206 p_dir = name[0:name.rfind('/') + 1]
207 pd_map[p_dir] = True
208 return list(pd_map.iterkeys())
209
210 def JoinWithTestExpectation(self, test_expectations):
211 """Join layout tests with the test expectation file using test name as key.
212
213 Args:
214 test_expectations: a test expectations object.
215
216 Returns:
217 test_info_map contains test name as key and another map as value. The
218 other map contains test description and the test expectation
219 information which contains keyword (e.g., 'GPU') as key (we do
220 not care about values). The map data structure is used since we
221 have to look up these keywords several times.
222 """
223 test_info_map = {}
224 for (lt_name, desc) in self.name_map.items():
225 test_info_map[lt_name] = {}
226 test_info_map[lt_name]['desc'] = desc
227 for (te_name, te_info) in (
228 test_expectations.all_test_expectation_info.items()):
229 if te_name == lt_name or (
230 te_name in lt_name and te_name.endswith('/')):
231 # Only keep the first match when found.
232 test_info_map[lt_name]['te_info'] = te_info
233 break
234 return test_info_map
235
236 @staticmethod
237 def GetTestDescriptionFromSVN(test_location,
238 root_path=DEFAULT_LAYOUTTEST_LOCATION):
239 """Get test description of a layout test from SVN.
240
241 Using urllib2.urlopen(), this method gets the entire HTML and extracts its
242 test description using |ExtractTestDescription()|.
243
244 Args:
245 test_location: the location of the layout test.
246 root_path: the root path of the Webkit SVN directory.
247
248 Returns:
249 A test description string.
250
251 Raises:
252 A URLError when the layout test is not available.
253 """
254 if test_location.endswith('.html'):
255 url = root_path + test_location
256 resp = urllib2.urlopen(url)
257 if resp.code == 200:
258 return LayoutTests.ExtractTestDescription(resp.read())
259 raise URLError('Fail to get layout test HTML file from %s.' % url)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698