test_converter.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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, Tag
  31. class W3CTestConverter(object):
  32. def __init__(self):
  33. self._host = Host()
  34. self._filesystem = self._host.filesystem
  35. self._host.initialize_scm()
  36. self._webkit_root = self._host.scm().checkout_root
  37. self.prefixed_properties = self.read_webkit_prefixed_css_property_list()
  38. def path_from_webkit_root(self, *comps):
  39. return self._filesystem.abspath(self._filesystem.join(self._webkit_root, *comps))
  40. def read_webkit_prefixed_css_property_list(self):
  41. prefixed_properties = []
  42. contents = self._filesystem.read_text_file(self.path_from_webkit_root('Source', 'WebCore', 'css', 'CSSPropertyNames.in'))
  43. for line in contents.splitlines():
  44. # Find lines starting with the -webkit- prefix.
  45. match = re.match('-webkit-[\w|-]*', line)
  46. if match:
  47. # Ignore lines where both the prefixed and non-prefixed property
  48. # are supported - denoted by -webkit-some-property = some-property.
  49. fields = line.split('=')
  50. if len(fields) == 2 and fields[1].strip() in fields[0].strip():
  51. continue
  52. prefixed_properties.append(match.group(0))
  53. return prefixed_properties
  54. def convert_for_webkit(self, new_path, filename):
  55. """ Converts a file's |contents| so it will function correctly in its |new_path| in Webkit.
  56. Returns the list of modified properties and the modified text if the file was modifed, None otherwise."""
  57. contents = self._filesystem.read_text_file(filename)
  58. if filename.endswith('.css'):
  59. return self.convert_css(contents)
  60. return self.convert_html(new_path, contents)
  61. def convert_css(self, contents):
  62. return self.add_webkit_prefix_to_unprefixed_properties(contents)
  63. def convert_html(self, new_path, contents):
  64. doc = BeautifulSoup(contents)
  65. did_modify_paths = self.convert_testharness_paths(doc, new_path)
  66. converted_properties_and_content = self.convert_prefixed_properties(doc)
  67. return converted_properties_and_content if (did_modify_paths or converted_properties_and_content[0]) else None
  68. def convert_testharness_paths(self, doc, new_path):
  69. """ Update links to testharness.js in the BeautifulSoup |doc| to point to the copy in |new_path|.
  70. Returns whether the document was modified."""
  71. # Look for the W3C-style path to any testharness files - scripts (.js) or links (.css)
  72. pattern = re.compile('/resources/testharness')
  73. script_tags = doc.findAll(src=pattern)
  74. link_tags = doc.findAll(href=pattern)
  75. testharness_tags = script_tags + link_tags
  76. if not testharness_tags:
  77. return False
  78. resources_path = self.path_from_webkit_root('LayoutTests', 'resources')
  79. resources_relpath = self._filesystem.relpath(resources_path, new_path)
  80. for tag in testharness_tags:
  81. attr = 'src'
  82. if tag.name != 'script':
  83. attr = 'href'
  84. old_path = tag[attr]
  85. new_tag = Tag(doc, tag.name, tag.attrs)
  86. new_tag[attr] = re.sub(pattern, resources_relpath + '/testharness', old_path)
  87. self.replace_tag(tag, new_tag)
  88. return True
  89. def convert_prefixed_properties(self, doc):
  90. """ Searches a BeautifulSoup |doc| for any CSS properties requiring the -webkit- prefix and converts them.
  91. Returns the list of converted properties and the modified document as a string """
  92. converted_properties = []
  93. # Look for inline and document styles.
  94. inline_styles = doc.findAll(style=re.compile('.*'))
  95. style_tags = doc.findAll('style')
  96. all_styles = inline_styles + style_tags
  97. for tag in all_styles:
  98. # Get the text whether in a style tag or style attribute.
  99. style_text = ''
  100. if tag.name == 'style':
  101. if not tag.contents:
  102. continue
  103. style_text = tag.contents[0]
  104. else:
  105. style_text = tag['style']
  106. updated_style_text = self.add_webkit_prefix_to_unprefixed_properties(style_text)
  107. # Rewrite tag only if changes were made.
  108. if updated_style_text[0]:
  109. converted_properties.extend(updated_style_text[0])
  110. new_tag = Tag(doc, tag.name, tag.attrs)
  111. new_tag.insert(0, updated_style_text[1])
  112. self.replace_tag(tag, new_tag)
  113. return (converted_properties, doc.prettify())
  114. def add_webkit_prefix_to_unprefixed_properties(self, text):
  115. """ Searches |text| for instances of properties requiring the -webkit- prefix and adds the prefix to them.
  116. Returns the list of converted properties and the modified text."""
  117. converted_properties = []
  118. for prefixed_property in self.prefixed_properties:
  119. unprefixed_property = prefixed_property.replace('-webkit-', '')
  120. # Look for the various ways it might be in the CSS
  121. # Match the the property preceded by either whitespace or left curly brace
  122. # or at the beginning of the string (for inline style attribute)
  123. pattern = '([\s{]|^)' + unprefixed_property + '(\s+:|:)'
  124. if re.search(pattern, text):
  125. print 'converting %s -> %s' % (unprefixed_property, prefixed_property)
  126. converted_properties.append(prefixed_property)
  127. text = re.sub(pattern, prefixed_property + ':', text)
  128. # FIXME: Handle the JS versions of these properties, too.
  129. return (converted_properties, text)
  130. def replace_tag(self, old_tag, new_tag):
  131. index = old_tag.parent.contents.index(old_tag)
  132. old_tag.parent.insert(index, new_tag)
  133. old_tag.extract()