3 # Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
9 # 1. Redistributions of source code must retain the above
10 # copyright notice, this list of conditions and the following
12 # 2. Redistributions in binary form must reproduce the above
13 # copyright notice, this list of conditions and the following
14 # disclaimer in the documentation and/or other materials
15 # provided with the distribution.
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
18 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
21 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22 # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27 # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 from webkitpy.common.host import Host
34 from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup as Parser
37 _log = logging.getLogger(__name__)
40 class TestParser(object):
42 def __init__(self, options, filename, host=Host()):
43 self.options = options
44 self.filename = filename
46 self.filesystem = self.host.filesystem
50 self.load_file(filename)
52 def load_file(self, filename, is_ref=False):
53 if self.filesystem.isfile(filename):
55 doc = Parser(self.filesystem.read_binary_file(filename))
57 # FIXME: Figure out what to do if we can't parse the file.
58 _log.error("Failed to parse %s", filename)
61 if self.filesystem.isdir(filename):
62 # FIXME: Figure out what is triggering this and what to do about it.
63 _log.error("Trying to load %s, which is a directory", filename)
71 def analyze_test(self, test_contents=None, ref_contents=None):
72 """ Analyzes a file to determine if it's a test, what type of test, and what reference or support files it requires. Returns all of the test info """
76 if test_contents is None and self.test_doc is None:
78 if test_contents is not None:
79 self.test_doc = Parser(test_contents)
80 if ref_contents is not None:
81 self.ref_doc = Parser(ref_contents)
83 # First check if it's a reftest
84 matches = self.reference_links_of_type('match') + self.reference_links_of_type('mismatch')
87 # FIXME: Is this actually true? We should fix this.
88 _log.warning('Multiple references are not supported. Importing the first ref defined in %s',
89 self.filesystem.basename(self.filename))
92 ref_file = self.filesystem.join(self.filesystem.dirname(self.filename), matches[0]['href'])
94 # FIXME: Figure out what to do w/ invalid test files.
95 _log.error('%s has a reference link but is missing the "href"', self.filesystem)
98 if (ref_file == self.filename):
99 return {'referencefile': self.filename}
101 if self.ref_doc is None:
102 self.load_file(ref_file, True)
104 test_info = {'test': self.filename, 'reference': ref_file}
106 # If the ref file does not live in the same directory as the test file, check it for support files
107 test_info['reference_support_info'] = {}
108 if self.filesystem.dirname(ref_file) != self.filesystem.dirname(self.filename):
109 reference_support_files = self.support_files(self.ref_doc)
110 if len(reference_support_files) > 0:
111 reference_relpath = self.filesystem.relpath(self.filesystem.dirname(self.filename), self.filesystem.dirname(ref_file)) + self.filesystem.sep
112 test_info['reference_support_info'] = {'reference_relpath': reference_relpath, 'files': reference_support_files}
114 # not all reference tests have a <link rel='match'> element in WPT repo
115 elif self.is_wpt_reftest():
116 test_info = {'test': self.filename, 'reference': self.potential_ref_filename()}
117 test_info['reference_support_info'] = {}
118 # we check for wpt manual test before checking for jstest, as some WPT manual tests can be classified as CSS JS tests
119 elif self.is_wpt_manualtest():
120 test_info = {'test': self.filename, 'manualtest': True}
121 elif self.is_jstest():
122 test_info = {'test': self.filename, 'jstest': True}
123 elif '-ref' in self.filename or 'reference' in self.filename:
124 test_info = {'referencefile': self.filename}
125 elif self.options['all'] is True:
126 test_info = {'test': self.filename}
130 def reference_links_of_type(self, reftest_type):
131 return self.test_doc.findAll(rel=reftest_type)
134 """Returns whether the file appears to be a jstest, by searching for usage of W3C-style testharness paths."""
135 return bool(self.test_doc.find(src=re.compile('[\'\"/]?/resources/testharness')))
137 def is_wpt_manualtest(self):
138 """Returns whether the test is a manual test according WPT rules (i.e. file ends with -manual.htm path)."""
139 return self.filename.endswith('-manual.htm') or self.filename.endswith('-manual.html')
141 def potential_ref_filename(self):
142 parts = self.filesystem.splitext(self.filename)
143 return parts[0] + '-ref' + parts[1]
145 def is_wpt_reftest(self):
146 """Returns whether the test is a ref test according WPT rules (i.e. file has a -ref.html counterpart)."""
147 parts = self.filesystem.splitext(self.filename)
148 return self.filesystem.isfile(self.potential_ref_filename())
150 def support_files(self, doc):
151 """ Searches the file for all paths specified in url()'s, href or src attributes."""
157 elements_with_src_attributes = doc.findAll(src=re.compile('.*'))
158 elements_with_href_attributes = doc.findAll(href=re.compile('.*'))
160 url_pattern = re.compile('url\(.*\)')
162 for url in doc.findAll(text=url_pattern):
163 url = re.search(url_pattern, url)
164 url = re.sub('url\([\'\"]?', '', url.group(0))
165 url = re.sub('[\'\"]?\)', '', url)
168 src_paths = [src_tag['src'] for src_tag in elements_with_src_attributes]
169 href_paths = [href_tag['href'] for href_tag in elements_with_href_attributes]
171 paths = src_paths + href_paths + urls
173 uri_scheme_pattern = re.compile(r"[A-Za-z][A-Za-z+.-]*:")
174 if not uri_scheme_pattern.match(path):
175 support_files.append(path)