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: 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 """A Module for LayoutTests.
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 find test description,
26 # this script tries to find 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
30 KEYWORDS_FOR_TEST_DESCRIPTION = (
31 ['This tests', 'This test', 'Test that', 'Tests that', 'Test '])
32
33 # If cannot find the keywords, this script tries to find test case
34 # description by the following tags.
35 TAGS_FOR_TEST_DESCRIPTION = (
36 ['title', 'p', 'div'])
37
38 # If cannot find the tags, this script tries to find the test case
39 # description in the sentence containing following words.
40 KEYWORD_FOR_TEST_DESCRIPTION_FAIL_SAFE = (
41 ['PASSED ', 'PASS:'])
42
43
44 class LayoutTests(object):
45 """A class to store test names in layout tests.
46
47 The test names (including regular expression patterns) are read from a CSV
48 file and used for getting layout test names from Webkit SVN.
49 """
50
51 def __init__(self, layouttest_root_path=DEFAULT_LAYOUTTEST_LOCATION,
52 csv_file_path=None):
53 """Initialize LayoutTests
54
55 Args:
56 layouttest_root_path: A location string where Webkit layout tests are
57 stored.
58 csv_file_path: CSV file path. The file contains a list of test names
59 in CSV format.
60 """
61 if csv_file_path:
62 filter_names = LayoutTests.GetLayoutTestNamesFromCSV(csv_file_path)
63 else:
64 filter_names = []
65 parent_location_list = LayoutTests.GetParentDirectoryList(filter_names)
66 if layouttest_root_path.startswith('http://'):
67 name_map = self.GetLayoutTestNamesFromSVN(parent_location_list,
68 layouttest_root_path)
69 else:
70 # TODO(imasaki): support other forms such as CSV for reading test names.
71 pass
72 self.name_map = copy.copy(name_map)
73 # Filter names.
74 for lt_name in name_map.keys():
75 match = False
76 for filter_name in filter_names:
77 if re.search(filter_name, lt_name):
78 match = True
79 break
80 if not match:
81 del self.name_map[lt_name]
82 # We get description only for the filtered names.
83 for lt_name in self.name_map.keys():
84 self.name_map[lt_name] = LayoutTests.GetTestDescriptionFromSVN(lt_name)
85
86 @staticmethod
87 def ExtractTestDescription(txt):
88 """Extract the description description from test code in HTML.
89
90 Currently, we have 4 rules described in the code below.
91 example can be fallen into rule 1):
92 <p>
93 This tests the intrinsic size of a video element is the default
94 300,150 before metadata is loaded, and 0,0 after
95 metadata is loaded for an audio-only file.
96 </p>
97 The strategy is very adhoc since the original test case files
98 (in HTML format) do not have standard way to store test description.
99
100 Args:
101 txt: A HTML text which may or may not contain test description.
102
103 Returns:
104 A string that contains test description. Returns 'UNKNOWN' if the
105 test description is not found.
106 """
107 # (1) Try to find test description contains keywords such as
108 # 'test that' and surrounded by p tag.
109 # We found this is the most common case.
110 for keyword in KEYWORDS_FOR_TEST_DESCRIPTION:
111 # Try to find <p> and </p>.
112 pattern = r'<p>(.*' + keyword + '.*)</p>'
113 matches = re.search(pattern, txt)
114 if matches is not None:
115 return matches.group(1).strip()
116
117 # (2) Try to find it by using more generic keywords such as 'PASS' etc.
118 for keyword in KEYWORD_FOR_TEST_DESCRIPTION_FAIL_SAFE:
119 # Try to find new lines.
120 pattern = r'\n(.*' + keyword + '.*)\n'
121 matches = re.search(pattern, txt)
122 if matches is not None:
123 # Remove 'p' tag.
124 text = matches.group(1).strip()
125 return text.replace('<p>', '').replace('</p>', '')
126
127 # (3) Try to find it by using THML tag such as title.
128 for tag in TAGS_FOR_TEST_DESCRIPTION:
129 pattern = r'<' + tag + '>(.*)</' + tag + '>'
130 matches = re.search(pattern, txt)
131 if matches is not None:
132 return matches.group(1).strip()
133
134 # (4) Try to find it by using test description and remove 'p' tag.
135 for keyword in KEYWORDS_FOR_TEST_DESCRIPTION:
136 # Try to find <p> and </p>.
137 pattern = r'\n(.*' + keyword + '.*)\n'
138 matches = re.search(pattern, txt)
139 if matches is not None:
140 # Remove 'p' tag.
141 text = matches.group(1).strip()
142 return text.replace('<p>', '').replace('</p>', '')
143
144 # (5) cannot find test description using existing rules.
145 # In this case, just returns 'UNKNOWN'
146 return 'UNKNOWN'
147
148 @staticmethod
149 def GetLayoutTestNamesFromSVN(parent_location_list,
150 layouttest_root_path):
151 """Get LayoutTest names from Webkit SVN.
152
153 Args:
154 parent_location_list: a list of locations of parents directory. This is
155 used when getting layout tests using PySVN.list().
156 layouttest_root_path: the root path of the Webkit SVN directory.
157
158 Returns:
159 a map containing test names as keys. The map is used de-dupe test names
160 as well.
161 """
162 client = pysvn.Client()
163 # Get directory structure in the Webkit SVN.
164 if parent_location_list is None:
165 # Try to get all the layout tests by enabling recursion option.
166 parent_location_list = ['/\S+\.html$']
167 recursion = True
168 else:
169 recursion = False
170 name_map = {}
171 for parent_location in parent_location_list:
172 if parent_location.endswith('/'):
173 file_list = client.list(layouttest_root_path + parent_location,
174 recurse=recursion)
175 for file_name in file_list:
176 if sys.stdout.isatty():
177 default_encoding = sys.stdout.encoding
178 else:
179 default_encoding = locale.getpreferredencoding()
180 file_name = file_name[0].repos_path.encode(default_encoding)
181 # Remove the word '/truck/LayoutTests'.
182 file_name = file_name.replace('/trunk/LayoutTests/', '')
183 if file_name.endswith('.html'):
184 name_map[file_name] = True
185 return name_map
186
187 @staticmethod
188 def GetLayoutTestNamesFromCSV(csv_file_path):
189 """Get layout test names from CSV file.
190
191 Args:
192 csv_file_path: the path for the CSV file containing test names (including
193 regular expression patterns).
194 """
195 file_object = file(csv_file_path, 'r')
196 reader = csv.reader(file_object)
197 names = []
198 for row in reader:
199 names.append(row[0])
200 file_object.close()
201 return names
202
203 @staticmethod
204 def GetParentDirectoryList(names):
205 """Get parent directory list from test names.
206
207 Args:
208 names : a list of test names. The test name also have path information as
209 well. For example, media/video-zoom.html.
210 """
211 pd_map = {}
212 for name in names:
213 p_dir = name[0:name.rfind('/') + 1]
214 pd_map[p_dir] = True
215 return list(pd_map.iterkeys())
216
217 def JoinWithTestExpectation(self, test_expections):
218 """Join layout tests with the test expectation file using test name as key.
219
220 Args:
221 test_expectaions: a test expectations object.
222
223 Returns:
224 test_info_map contains test name as key and another map as value. The
225 map contains test description and the test expectation information
226 which contains keyword (e.g., 'GPU') as key.
227 """
228 test_info_map = {}
229 for (lt_name, desc) in self.name_map.items():
230 test_info_map[lt_name] = {}
231 test_info_map[lt_name]['desc'] = desc
232 for (te_name, te_info) in (
233 test_expections.all_test_expectation_info.items()):
234 if te_name == lt_name or (
235 te_name in lt_name and te_name.endswith('/')):
236 # Only 1 match (if exist)
237 test_info_map[lt_name]['te_info'] = te_info
238 break
239 return test_info_map
240
241 @staticmethod
242 def GetTestDescriptionFromSVN(test_location,
243 layouttest_root_path=DEFAULT_LAYOUTTEST_LOCATION):
244 """Get test description of a layout test from SVN.
245
246 Using urllib2.urlopen(), this method gets the entire HTML and extract test
247 description.
248
249 Args:
250 test_location: the location of the layout test
251 layouttest_root_path: the root path of the Webkit SVN directory.
252
253 Returns:
254 A test description string.
255
256 raises:
257 A URLError when the layout test is not available.
258 """
259 if test_location.endswith('.html'):
260 resp = urllib2.urlopen(layouttest_root_path + test_location)
261 if resp.code == 200:
262 return LayoutTests.ExtractTestDescription(resp.read())
263 raise URLError
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698