testfuncs.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. """
  2. Copyright (c) Contributors to the Open 3D Engine Project.
  3. For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. SPDX-License-Identifier: Apache-2.0 OR MIT
  5. """
  6. #!/usr/bin/python
  7. # -*- coding: utf-8 -*-
  8. import re
  9. import subprocess
  10. import sys
  11. def findTokenToInt(output, expression):
  12. castStringToInt = lambda str : int(str) if str.isdigit() else -2
  13. #errorCode = re.search(r"Error\s\d*\s:", output)
  14. errorCode = re.search(expression, output)
  15. if not errorCode:
  16. return -1
  17. else:
  18. errorCode = re.sub(r"\D","", errorCode.group())
  19. errorCode = castStringToInt(errorCode)
  20. return errorCode
  21. def firstof(haystack, *needles):
  22. finds = [haystack.decode('utf-8').find(n) for n in needles]
  23. if all(e == -1 for e in finds):
  24. return -1
  25. return min([e for e in finds if e != -1])
  26. def clean(str):
  27. return str.strip().strip('"').strip("'")
  28. def verifyPartitionPred(operands):
  29. if operands[1] == '==':
  30. return operands[0] == operands[2]
  31. if operands[1] == '!=':
  32. return operands[0] != operands[2]
  33. def executePredicateChecks(message):
  34. numchecked = 0
  35. lookfor = "@check predicate"
  36. for m in re.finditer(lookfor, message.decode('utf-8')):
  37. numchecked = numchecked + 1
  38. st = m.start() + len(lookfor)
  39. leftover = message[st:]
  40. stop = firstof(leftover, '\\n', '\n', '"@')
  41. wholeexpr = leftover[:stop]
  42. operands = wholeexpr.decode('utf-8').partition("==")
  43. operands = [clean(s) for s in operands]
  44. if not verifyPartitionPred(operands):
  45. print ("TEST error:", operands)
  46. return (False, numchecked)
  47. return (True, numchecked)
  48. def launchCompiler(compilerPath, options, silent):
  49. '''returns a tuple (standard-output-text, process-return-code)'''
  50. arglist = [compilerPath]
  51. arglist.extend(options)
  52. print (" Running: ", ' '.join(arglist))
  53. process = subprocess.Popen(arglist, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  54. out, err = process.communicate()
  55. if not silent:
  56. sys.stdout.write(out.decode('utf-8'))
  57. sys.stderr.write(err.decode('utf-8'))
  58. return (out, err, process.returncode)
  59. def parseYaml(text):
  60. '''designed to read-in the output of --dumpsym'''
  61. try:
  62. import yaml
  63. #from yaml import CLoader as Loader
  64. except ImportError:
  65. print ("no yaml module. execute `pip install pyyaml`")
  66. return None
  67. try:
  68. return yaml.load(text, Loader=yaml.FullLoader)
  69. except yaml.YAMLError as e:
  70. print ("Parsing YAML string failed")
  71. if hasattr(e, "reason"):
  72. print ("Reason:", e.reason)
  73. print ("At position: {0} (line {1}) with encoding {2}".format(e.position, len(text[0:e.position].splitlines()), e.encoding))
  74. print ("Invalid char code:", e.character)
  75. print ("culprit context:", text[e.position - 8 : e.position + 8])
  76. else: raise
  77. raise
  78. except AttributeError as ae:
  79. if "has no attribute 'FullLoader'" in str(ae):
  80. return yaml.load(text)
  81. else: raise
  82. def buildAndGetSymbols(thefile, compilerPath, silent, extraArgs=[]):
  83. '''returns tuple: (symbols-in-algebraic-form, ok-bool)'''
  84. import clr
  85. stdout, stderr, code = launchCompiler(compilerPath, [thefile, "--dumpsym"] + extraArgs, silent)
  86. if code != 0:
  87. if not silent: print (clr.fg.RED + clr.style.BRIGHT + "compilation failed " + clr.style.NORMAL + thefile + clr.style.RESET_ALL)
  88. return (None, False)
  89. else:
  90. symbols = parseYaml(stdout)
  91. if symbols is None:
  92. print (clr.fg.RED + "Parsing result of --dumpsym failed" + clr.style.RESET_ALL)
  93. return (None, False)
  94. return (symbols, code == 0)
  95. def buildAndGetJson(thefile, compilerPath, silent, extraArgs):
  96. '''returns tuple: (layouts-in-json-format, ok-bool)'''
  97. import clr
  98. import json
  99. stdout, stderr, code = launchCompiler(compilerPath, [thefile] + extraArgs, silent)
  100. if code != 0:
  101. if not silent: print (clr.fg.RED + clr.style.BRIGHT + "compilation failed " + clr.style.NORMAL + str(extraArgs) + " " + thefile + clr.style.RESET_ALL)
  102. return (None, False)
  103. else:
  104. j = json.loads(stdout)
  105. if j is None:
  106. print (clr.fg.RED + "Parsing result of " + extraArgs + " failed" + clr.style.RESET_ALL)
  107. return (None, False)
  108. return (j, code == 0)
  109. def buildAndGet(thefile, compilerPath, silent, extraArgs):
  110. '''returns tuple: (stdout, ok-bool)'''
  111. import clr
  112. #force silent
  113. stdout, stderr, code = launchCompiler(compilerPath, [thefile] + extraArgs, True)
  114. if code != 0:
  115. if not silent: print (clr.fg.RED + "compilation of " + thefile + " failed" + clr.style.RESET_ALL)
  116. return (None, False)
  117. return (stdout, code == 0)
  118. def buildAndGetError(thefile, compilerPath, silent, extraArgs):
  119. '''returns tuple: (stderr, failed-bool)'''
  120. import clr
  121. #force silent
  122. stdout, stderr, code = launchCompiler(compilerPath, [thefile] + extraArgs, True)
  123. if code == 0:
  124. if not silent: print (clr.fg.RED + "compilation of " + thefile + " succeeded. Was expecting failure." + clr.style.RESET_ALL)
  125. return (None, False)
  126. return (stderr, code != 0)
  127. def dumpKeywords(compilerPath):
  128. '''returns tuple: (categorized-tokens-in-algebraic-form, ok-bool)'''
  129. import clr
  130. stdout, stderr, code = launchCompiler(compilerPath, ["--listpredefined"], False)
  131. if code != 0:
  132. print (clr.fg.RED + "compilation failed" + clr.style.RESET_ALL)
  133. return (None, False)
  134. else:
  135. tokens = parseYaml(stdout)
  136. if tokens is None:
  137. print (clr.fg.RED + "Parsing result of --listpredefined failed" + clr.style.RESET_ALL)
  138. return (None, False)
  139. return (tokens, code == 0)
  140. def verifyAllPredicates(predicates, code, silent=True):
  141. import clr
  142. import pprint
  143. import inspect
  144. allok = True
  145. for i, p in enumerate(predicates):
  146. ok = True
  147. try:
  148. ok = p()
  149. except Exception as e:
  150. print (clr.fg.RED + "exception " + clr.style.RESET_ALL + str(e))
  151. ok = False
  152. if not ok:
  153. try: src=inspect.getsource(p)
  154. except: src="<exception>"
  155. print (clr.fg.RED + "FAIL (" + str(i) + "):" + clr.style.RESET_ALL + src)
  156. allok = allok and ok
  157. if not allok and not silent:
  158. print ("dump as parsed:")
  159. pp = pprint.PrettyPrinter(indent=2, width=160)
  160. pp.pprint(code)
  161. return allok