bdb24dfd656da1dbe11bedd8adcbe49743633313
[WebKit-https.git] / Tools / Scripts / webkitpy / w3c / test_parser.py
1 #!/usr/bin/env python
2
3 # Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 #
9 # 1. Redistributions of source code must retain the above
10 #    copyright notice, this list of conditions and the following
11 #    disclaimer.
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.
16 #
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
28 # SUCH DAMAGE.
29
30 import re
31
32 from webkitpy.common.host import Host
33 from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup as Parser
34
35
36 class TestParser(object):
37
38     def __init__(self, options, filename):
39         self.options = options
40         self.filename = filename
41         self.host = Host()
42         self.filesystem = self.host.filesystem
43
44         self.test_doc = None
45         self.ref_doc = None
46         self.load_file(filename)
47
48     def load_file(self, filename):
49         if self.filesystem.exists(filename):
50             self.test_doc = Parser(self.filesystem.read_text_file(filename))
51         else:
52             self.test_doc = None
53         self.ref_doc = None
54
55     def analyze_test(self, test_contents=None, ref_contents=None):
56         """ 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 """
57
58         test_info = None
59
60         if test_contents is None and self.test_doc is None:
61             return test_info
62
63         if test_contents is not None:
64             self.test_doc = Parser(test_contents)
65
66         if ref_contents is not None:
67             self.ref_doc = Parser(ref_contents)
68
69         # First check if it's a reftest
70
71         matches = self.reference_links_of_type('match') + self.reference_links_of_type('mismatch')
72         if matches:
73             if len(matches) > 1:
74                 print 'Warning: Webkit does not support multiple references. Importing the first ref defined in ' + self.filesystem.basename(self.filename)
75
76             ref_file = self.filesystem.join(self.filesystem.dirname(self.filename), matches[0]['href'])
77             if self.ref_doc is None:
78                 self.ref_doc = self.load_file(ref_file)
79
80             test_info = {'test': self.filename, 'reference': ref_file}
81
82             # If the ref file path is relative, we need to check it for
83             # relative paths also because when it lands in WebKit, it will be
84             # moved down into the test dir.
85             #
86             # Note: The test files themselves are not checked for support files
87             # outside their directories as the convention in the CSSWG is to
88             # put all support files in the same dir or subdir as the test.
89             #
90             # All non-test files in the test's directory tree are normally
91             # copied as part of the import as they are assumed to be required
92             # support files.
93             #
94             # *But*, there is exactly one case in the entire css2.1 suite where
95             # at test depends on a file that lives in a different directory,
96             # which depends on another file that lives outside of its
97             # directory. This code covers that case :)
98             if matches[0]['href'].startswith('..'):
99                 support_files = self.support_files(self.ref_doc)
100                 test_info['refsupport'] = support_files
101
102         elif self.is_jstest():
103             test_info = {'test': self.filename, 'jstest': True}
104         elif self.options['all'] is True and not('-ref' in self.filename) and not('reference' in self.filename):
105             test_info = {'test': self.filename}
106
107         return test_info
108
109     def reference_links_of_type(self, reftest_type):
110         return self.test_doc.findAll(rel=reftest_type)
111
112     def is_jstest(self):
113         """Returns whether the file appears to be a jstest, by searching for usage of W3C-style testharness paths."""
114         return bool(self.test_doc.find(src=re.compile('[\'\"/]?/resources/testharness')))
115
116     def support_files(self, doc):
117         """ Searches the file for all paths specified in url()'s, href or src attributes."""
118         support_files = []
119
120         if doc is None:
121             return support_files
122
123         elements_with_src_attributes = doc.findAll(src=re.compile('.*'))
124         elements_with_href_attributes = doc.findAll(href=re.compile('.*'))
125
126         url_pattern = re.compile('url\(.*\)')
127         urls = []
128         for url in doc.findAll(text=url_pattern):
129             url = re.search(url_pattern, url)
130             url = re.sub('url\([\'\"]', '', url.group(0))
131             url = re.sub('[\'\"]\)', '', url)
132             urls.append(url)
133
134         src_paths = [src_tag['src'] for src_tag in elements_with_src_attributes]
135         href_paths = [href_tag['href'] for href_tag in elements_with_href_attributes]
136
137         paths = src_paths + href_paths + urls
138         for path in paths:
139             if not(path.startswith('http:')) and not(path.startswith('mailto:')):
140                 support_files.append(path)
141
142         return support_files