Create a script to import W3C tests
[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 import os
30 import re
31
32 from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup as Parser
33
34
35 class TestParser(object):
36
37     def __init__(self, options, filename):
38         self.options = options
39         self.filename = filename
40         self.test_doc = self.load_file(filename)
41         self.ref_doc = None
42
43     def load_file(self, file_to_parse):
44         """ Opens and read the |file_to_parse| """
45         doc = None
46
47         if os.path.exists(file_to_parse):
48             f = open(file_to_parse)
49             html = f.read()
50             f.close()
51
52             doc = Parser(html)
53
54         return doc
55
56     def analyze_test(self, test_contents=None, ref_contents=None):
57         """ 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 """
58
59         test_info = None
60
61         if test_contents is None and self.test_doc is None:
62             return test_info
63
64         if test_contents is not None:
65             self.test_doc = Parser(test_contents)
66
67         if ref_contents is not None:
68             self.ref_doc = Parser(ref_contents)
69
70         # First check if it's a reftest
71         matches = self.get_reftests(True)
72         if len(matches) != 0:
73
74             if len(matches) > 1:
75                 print 'Warning: Webkit does not support multiple references. Importing the first ref defined in ' + os.path.basename(self.filename)
76
77             ref_file = os.path.join(os.path.dirname(self.filename), matches[0]['href'])
78             if self.ref_doc is None:
79                 self.ref_doc = self.load_file(ref_file)
80
81             test_info = {'test': self.filename, 'reference': ref_file}
82
83             # If the ref file path is relative, we need to check it for relative paths
84             # because when it lands in Webkit, it will be moved down into the test dir
85             # Note: The test files themselves are not checked for support files
86             # that live outside their directories as it's the convention in the CSSWG
87             # to put all support files in the same dir or subdir as the test. All non-test
88             # files in the test's directory tree are automatically copied as part of the import as
89             # they are assumed to be required support files There is exactly one case in the entire
90             # css2.1 suite where at test depends on a file that lives in a different directory, which
91             # depends on another file that lives outside of its directory. This code covers that case :)
92             if matches[0]['href'].startswith('..'):
93                 supportFiles = self.get_support_files(self.ref_doc)
94                 test_info['refsupport'] = supportFiles
95
96         # Next, if it's a JS test
97         elif self.is_jstest():
98             test_info = {'test': self.filename, 'jstest': True}
99
100         # Or if we explicitly want everything
101         elif self.options['all'] is True and \
102              not('-ref' in self.filename) and \
103              not('reference' in self.filename):
104             test_info = {'test': self.filename}
105
106         # Courtesy check and warning if there are any mismatches
107         mismatches = self.get_reftests(False)
108         if len(mismatches) != 0:
109             print "Warning: Webkit does not support mismatch references. Ignoring mismatch defined in " + os.path.basename(self.filename)
110
111         return test_info
112
113     def get_reftests(self, find_match):
114         """ Searches for all reference links in the file. If |find_match| is searches for matches, otherwise for mismatches """
115
116         if find_match:
117             return self.test_doc.findAll(rel='match')
118         else:
119             return self.test_doc.findAll(rel='mismatch')
120
121     def is_jstest(self):
122         """ Searches the file for usage of W3C-style testharness paths """
123
124         if self.test_doc.find(src=re.compile('[\'\"/]?/resources/testharness')) is None:
125             return False
126         else:
127             return True
128
129     def get_support_files(self, doc):
130         """ Searches the file for all paths specified in url()'s, href or src attributes """
131
132         support_files = []
133
134         if doc is None:
135             return support_files
136
137         # Look for tags with src or href attributes
138         src_attrs = doc.findAll(src=re.compile('.*'))
139         href_attrs = doc.findAll(href=re.compile('.*'))
140
141         # Look for urls
142         url_pattern = re.compile('url\(.*\)')
143         urls = []
144         for url in doc.findAll(text=url_pattern):
145             url = re.search(url_pattern, url)
146             url = re.sub('url\([\'\"]', '', url.group(0))
147             url = re.sub('[\'\"]\)', '', url)
148             urls.append(url)
149
150         src_paths = [src_tag['src'] for src_tag in src_attrs]
151         href_paths = [href_tag['href'] for href_tag in href_attrs]
152
153         paths = src_paths + href_paths + urls
154         for path in paths:
155             # Ignore http and mailto links
156             if not(path.startswith('http:')) and \
157                not(path.startswith('mailto:')):
158                 support_files.append(path)
159
160         return support_files