PageRenderTime 59ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/hphp/hack/test/h2tp/convert_hhvm_collection_base.py

http://github.com/facebook/hiphop-php
Python | 192 lines | 182 code | 8 blank | 2 comment | 14 complexity | 231b9bc6488dd949aaedc773f75aeb21 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, MIT, LGPL-2.0, Apache-2.0
  1. from __future__ import absolute_import
  2. from __future__ import division
  3. from __future__ import unicode_literals
  4. from __future__ import print_function
  5. from .engine import PHP5
  6. from .converter import Converter
  7. import unittest
  8. import os
  9. import tempfile
  10. import difflib
  11. import shutil
  12. import glob
  13. import re
  14. class ConvertHHVMCollectionBase(unittest.TestCase):
  15. def setUp(self):
  16. self.converter = Converter(self.binary_path())
  17. self.engine = PHP5(self.execution_prefix())
  18. def verify(self):
  19. tmp = tempfile.mkdtemp()
  20. tmpInput = os.path.join(tmp, 'input')
  21. shutil.copytree(self.testsDir(), tmpInput)
  22. self.delete_unsupported_inputs(tmpInput)
  23. tmpOutput = os.path.join(tmp, 'output')
  24. (success, output) = self.converter.convert(tmpInput, tmpOutput, [])
  25. if success:
  26. files = (glob.glob(tmpOutput + '/*.php') +
  27. glob.glob(tmpOutput + '/**/*.php'))
  28. if self.engine.exists():
  29. self.check_files(tmpOutput, files)
  30. # if we get here without errors, delete the tree
  31. shutil.rmtree(tmp)
  32. else:
  33. self.fail("error converting hhvm collection tests\n" + output)
  34. def delete_unsupported_inputs(self, dir):
  35. all_files = [f for files in UNSUPPORTED_INPUTS.values() for f in files]
  36. all_files += [f for files in MISMATCHED_FILES.values() for f in files]
  37. for f in all_files:
  38. os.remove(os.path.join(dir, f))
  39. def normalize(self, string):
  40. string = string.lstrip()
  41. for (patt, repl) in NORMALIZING_TUPLES:
  42. string = re.sub(patt, repl, string)
  43. # add a trailing newline so that its easier to see the diff
  44. return string.rstrip() + "\n"
  45. def execute_file(self, f):
  46. (success, output) = self.engine.execute_file(f)
  47. output = self.normalize(output)
  48. return re.sub(SET_RE, fix_set_output, output)
  49. def check_files(self, outdir, files):
  50. for f in files:
  51. actual_output = self.execute_file(f)
  52. exp_f = f + '.expect' if os.path.isfile(f + '.expect') else (f +
  53. '.expectf')
  54. with open(exp_f, "r") as exp_fo:
  55. expected_output = self.normalize(exp_fo.read())
  56. if (actual_output != expected_output):
  57. message = ''.join(difflib.unified_diff(
  58. expected_output.splitlines(True),
  59. actual_output.splitlines(True)))
  60. self.fail(
  61. "Output not expected at " +
  62. f +
  63. " :\n"
  64. + message)
  65. #non matching files
  66. MISMATCHED_FILES = {
  67. "array functions operating on collections": [
  68. 'array-diff-1.php',
  69. 'array-diff-2.php',
  70. 'array-intersect-1.php',
  71. 'array-intersect-2.php',
  72. 'array_fill_keys.php',
  73. 'array-unshift.php',
  74. 'array-filter.php',
  75. 'array_reverse.php',
  76. 'array-diff-key-1.php',
  77. 'array-diff-key-2.php',
  78. 'array-intersect-key-1.php',
  79. 'array-intersect-key-2.php',
  80. 'array-shift.php',
  81. 'array_combine.php',
  82. 'array_slice.php',
  83. '841.php',
  84. 'call-user-func-array.php',
  85. 'implode.php',
  86. 'array-typehint.php',
  87. 'set-sort.php',
  88. 'array_flip.php',
  89. 'array-pop.php',
  90. 'array_push.php',
  91. 'array_keys.php',
  92. 'array_search_funcs.php',
  93. 'array_chunk.php',
  94. 'array-map.php',
  95. 'frozen_vector/materialization.php',
  96. 'frozen_vector/array_key_exists.php',
  97. 'frozen_map/api.php',
  98. 'frozen_map/constructors.php',
  99. 'frozen_map/materialization.php',
  100. 'array_values.php',
  101. 'collection-isset.php'
  102. ],
  103. "dependence on internal implementation -- var_export, serialize": [
  104. '836.php',
  105. '809.php',
  106. 'frozen_set/serialization.php',
  107. 'frozen_set/cow_large.php',
  108. 'migration/unserialize-pair.php',
  109. 'migration/unserialize-set.php',
  110. 'migration/unserialize-vector.php',
  111. 'migration/unserialize-map.php',
  112. 'frozen_vector/cow_large.php',
  113. 'vector_map_private.php',
  114. ],
  115. "custom var_dump for string vs int keys": [
  116. 'dup_keys.php',
  117. 'set-brackets-at-get.php',
  118. 'set-invalid-operations.php',
  119. ],
  120. "detection of indirect access": [
  121. 'invalid-operations.php'
  122. ],
  123. "requires apc functions": [
  124. '839.php',
  125. '840.php'
  126. ],
  127. }
  128. #map of all files that we cannot convert at the moment
  129. UNSUPPORTED_INPUTS = {
  130. 'parse error': [
  131. '806.php',
  132. '807.php',
  133. '808.php',
  134. '813.php',
  135. '814.php',
  136. '815.php',
  137. '823.php',
  138. 'concat.php',
  139. 'empty_vector.php',
  140. 'imm-iteration-bug.php',
  141. 'vector-addall.php',
  142. ],
  143. 'PHP files are not supported': [
  144. 'iterator-clone-bug.php',
  145. 'preg-replace.php',
  146. 'set-addall-bug.php',
  147. ],
  148. 'c_user_attributes not supported': [
  149. 'extend-collection-test.php'
  150. ],
  151. 'instance initializers not supported': [
  152. 'deep_copy.php',
  153. 'prop_init_literal_bug.php',
  154. 'prop_init_trait_bug.php'
  155. ]
  156. }
  157. def fix_set_output(m):
  158. middle = m.group(3).split('\n')
  159. middle = '\n'.join(middle[1::2])
  160. middle = '\n' + middle if middle != '' else middle
  161. return "object(" + m.group(1) + ")" + m.group(2) + middle + "\n}"
  162. SET_RE = re.compile("object\((HH\\\\(?:Imm)?Set)\)(.*)\n([^\}]*)\}")
  163. NORMALIZING_TUPLES = [
  164. # indirect access can only be prevented by regular php code, we cannot
  165. # detect it and throw errors. However, in that case the system will
  166. # trigger an error with the level E_NOTICE
  167. (re.compile("PHP Notice: Illegal member variable name.*"), ""),
  168. # strip trailing spaces
  169. (re.compile("\s*\n"), "\n"),
  170. # replace object ids in var_dumps with the string ID
  171. (re.compile("(object\(.*\)#)(\d+)(.*)"), r"\1ID\3"),
  172. # convert warnings and fatal from the user level error strings to system
  173. # level error strings
  174. (re.compile("(?:PHP )?(Warning:|Fatal error:)(\s)+(.*in ).*"), r"\1 \3"),
  175. # delete stack traces
  176. (re.compile("Stack trace:.*", re.DOTALL), "")
  177. ]