blob: cb38d0d52c9bdd22bf6cf7fb4bbee1b6dbbeabf3 [file] [log] [blame]
# Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
import logging
import re
try:
from pathlib import Path
except ImportError:
from pathlib2 import Path
from webkitpy.common.host import Host
from webkitpy.common.system.filesystem_mock import MockFileSystem
from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup as Parser
from webkitpy.thirdparty.wpt.manifest.sourcefile import SourceFile
_log = logging.getLogger(__name__)
class TestParser(object):
def __init__(self, options, filename, host=None, source_root_directory=None):
self.options = options
self.filename = filename
self.host = Host() if host is None else host
self.filesystem = self.host.filesystem
self.source_root_directory = source_root_directory
def analyze_test(self, test_contents=None, ref_contents=None):
""" 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 """
test_info = None
if test_contents is None and isinstance(self.host.filesystem, MockFileSystem):
test_contents = self.filesystem.read_binary_file(self.filename)
if self.source_root_directory is None:
source_root_directory = Path(self.filename).anchor
else:
source_root_directory = self.source_root_directory
wpt_sourcefile = SourceFile(
source_root_directory,
self.filesystem.relpath(self.filename, source_root_directory),
"/",
contents=test_contents,
)
test_type, test_items = wpt_sourcefile.manifest_items()
if test_type == "manual":
test_info = {'test': self.filename, 'manualtest': True}
elif test_type == "reftest":
assert len(test_items) == 1
test_item = test_items[0]
matches = [ref for ref in test_item.references if ref[1] == "=="]
mismatches = [ref for ref in test_item.references if ref[1] == "!="]
if len(matches) > 1 or len(mismatches) > 1:
# FIXME: Is this actually true? We should fix this.
_log.warning('Multiple references of the same type are not supported. Importing the first ref defined in %s',
self.filesystem.basename(self.filename))
test_info = {'test': self.filename}
refs_to_import = matches[0:1] + mismatches[0:1]
for (href_match_file, reference_type) in refs_to_import:
if href_match_file.startswith('/'):
ref_file = self.filesystem.join(source_root_directory, href_match_file.lstrip('/'))
else:
ref_file = self.filesystem.join(self.filesystem.dirname(self.filename), href_match_file)
assert reference_type in ("==", "!=")
reference_type = "match" if reference_type == "==" else "mismatch"
if ref_contents is not None:
ref_doc = Parser(ref_contents)
elif self.filesystem.exists(ref_file):
ref_doc = Parser(self.filesystem.read_binary_file(ref_file))
else:
ref_doc = None
test_info[reference_type + '_reference'] = ref_file
test_info[reference_type + '_reference_support_info'] = {}
# If the ref file does not live in the same directory as the test file, check it for support files
if self.filesystem.dirname(ref_file) != self.filesystem.dirname(self.filename):
reference_support_files = self.support_files(ref_doc)
if len(reference_support_files) > 0:
reference_relpath = self.filesystem.relpath(self.filesystem.dirname(self.filename), self.filesystem.dirname(ref_file)) + self.filesystem.sep
test_info[reference_type + '_reference_support_info'] = {'reference_relpath': reference_relpath, 'files': reference_support_files}
elif test_type == "crashtest":
test_info = {'test': self.filename, 'crashtest': True}
elif test_type == "testharness":
test_info = {'test': self.filename, 'jstest': True}
elif self.options['all'] is True:
test_info = {'test': self.filename}
if test_info and wpt_sourcefile.timeout == "long":
test_info['slow'] = True
return test_info
def support_files(self, doc):
""" Searches the file for all paths specified in url()'s, href or src attributes."""
support_files = []
if doc is None:
return support_files
elements_with_src_attributes = doc.findAll(src=re.compile('.*'))
elements_with_href_attributes = doc.findAll(href=re.compile('.*'))
url_pattern = re.compile(r'url\(.*\)')
urls = []
for url in doc.findAll(text=url_pattern):
for url in re.findall(url_pattern, url):
url = re.sub('url\\([\'\"]?', '', url)
url = re.sub('[\'\"]?\\)', '', url)
urls.append(url)
src_paths = [src_tag['src'] for src_tag in elements_with_src_attributes]
href_paths = [href_tag['href'] for href_tag in elements_with_href_attributes]
paths = src_paths + href_paths + urls
for path in paths:
uri_scheme_pattern = re.compile(r"[A-Za-z][A-Za-z+.-]*:")
if not uri_scheme_pattern.match(path):
support_files.append(path)
return support_files