test_parser.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. #!/usr/bin/env python
  2. # Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
  3. #
  4. # Redistribution and use in source and binary forms, with or without
  5. # modification, are permitted provided that the following conditions
  6. # are met:
  7. #
  8. # 1. Redistributions of source code must retain the above
  9. # copyright notice, this list of conditions and the following
  10. # disclaimer.
  11. # 2. Redistributions in binary form must reproduce the above
  12. # copyright notice, this list of conditions and the following
  13. # disclaimer in the documentation and/or other materials
  14. # provided with the distribution.
  15. #
  16. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
  17. # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  19. # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  20. # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  21. # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  22. # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  23. # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  25. # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  26. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. # SUCH DAMAGE.
  28. import re
  29. from webkitpy.common.host import Host
  30. from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup as Parser
  31. class TestParser(object):
  32. def __init__(self, options, filename):
  33. self.options = options
  34. self.filename = filename
  35. self.host = Host()
  36. self.filesystem = self.host.filesystem
  37. self.test_doc = None
  38. self.ref_doc = None
  39. self.load_file(filename)
  40. def load_file(self, filename):
  41. if self.filesystem.exists(filename):
  42. self.test_doc = Parser(self.filesystem.read_text_file(filename))
  43. else:
  44. self.test_doc = None
  45. self.ref_doc = None
  46. def analyze_test(self, test_contents=None, ref_contents=None):
  47. """ 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 """
  48. test_info = None
  49. if test_contents is None and self.test_doc is None:
  50. return test_info
  51. if test_contents is not None:
  52. self.test_doc = Parser(test_contents)
  53. if ref_contents is not None:
  54. self.ref_doc = Parser(ref_contents)
  55. # First check if it's a reftest
  56. matches = self.reference_links_of_type('match') + self.reference_links_of_type('mismatch')
  57. if matches:
  58. if len(matches) > 1:
  59. print 'Warning: Webkit does not support multiple references. Importing the first ref defined in ' + self.filesystem.basename(self.filename)
  60. ref_file = self.filesystem.join(self.filesystem.dirname(self.filename), matches[0]['href'])
  61. if self.ref_doc is None:
  62. self.ref_doc = self.load_file(ref_file)
  63. test_info = {'test': self.filename, 'reference': ref_file}
  64. # If the ref file path is relative, we need to check it for
  65. # relative paths also because when it lands in WebKit, it will be
  66. # moved down into the test dir.
  67. #
  68. # Note: The test files themselves are not checked for support files
  69. # outside their directories as the convention in the CSSWG is to
  70. # put all support files in the same dir or subdir as the test.
  71. #
  72. # All non-test files in the test's directory tree are normally
  73. # copied as part of the import as they are assumed to be required
  74. # support files.
  75. #
  76. # *But*, there is exactly one case in the entire css2.1 suite where
  77. # at test depends on a file that lives in a different directory,
  78. # which depends on another file that lives outside of its
  79. # directory. This code covers that case :)
  80. if matches[0]['href'].startswith('..'):
  81. support_files = self.support_files(self.ref_doc)
  82. test_info['refsupport'] = support_files
  83. elif self.is_jstest():
  84. test_info = {'test': self.filename, 'jstest': True}
  85. elif self.options['all'] is True and not('-ref' in self.filename) and not('reference' in self.filename):
  86. test_info = {'test': self.filename}
  87. return test_info
  88. def reference_links_of_type(self, reftest_type):
  89. return self.test_doc.findAll(rel=reftest_type)
  90. def is_jstest(self):
  91. """Returns whether the file appears to be a jstest, by searching for usage of W3C-style testharness paths."""
  92. return bool(self.test_doc.find(src=re.compile('[\'\"/]?/resources/testharness')))
  93. def support_files(self, doc):
  94. """ Searches the file for all paths specified in url()'s, href or src attributes."""
  95. support_files = []
  96. if doc is None:
  97. return support_files
  98. elements_with_src_attributes = doc.findAll(src=re.compile('.*'))
  99. elements_with_href_attributes = doc.findAll(href=re.compile('.*'))
  100. url_pattern = re.compile('url\(.*\)')
  101. urls = []
  102. for url in doc.findAll(text=url_pattern):
  103. url = re.search(url_pattern, url)
  104. url = re.sub('url\([\'\"]', '', url.group(0))
  105. url = re.sub('[\'\"]\)', '', url)
  106. urls.append(url)
  107. src_paths = [src_tag['src'] for src_tag in elements_with_src_attributes]
  108. href_paths = [href_tag['href'] for href_tag in elements_with_href_attributes]
  109. paths = src_paths + href_paths + urls
  110. for path in paths:
  111. if not(path.startswith('http:')) and not(path.startswith('mailto:')):
  112. support_files.append(path)
  113. return support_files