Python Library Unittest
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test.py 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. import logging
  5. logger = logging.getLogger('__unittest__')
  6. REPORT_LEVEL_FAIL = logging.ERROR
  7. REPORT_LEVEL_INSPECT = logging.WARNING
  8. REPORT_LEVEL_PASS = logging.INFO
  9. def __get_repr__(value, data_filter=repr):
  10. if type(value) == dict:
  11. return '{ ' + ', '.join(['%s: %s' % (repr(key), __get_repr__(value.get(key))) for key in value.keys()]) + ' }'
  12. elif type(value) == list:
  13. return '[ ' + ', '.join(['%s' % (__get_repr__(v)) for v in value]) + ' ]'
  14. else:
  15. return data_filter(value)
  16. def __report_result__(result, description, data_filter=repr):
  17. logger.debug('Result (%s): %s (%s)', description, __get_repr__(result, data_filter), repr(type(result)))
  18. def __report_expectation_equivalency__(expectation, description, data_filter=repr):
  19. logger.debug('Expectation (%s): result = %s (%s)', description, __get_repr__(expectation, data_filter), repr(type(expectation)))
  20. def __report_expectation_inlist__(expectation, description, data_filter=repr):
  21. logger.debug('Expectation (%s): %s in result', description, __get_repr__(expectation, data_filter))
  22. def __report_expectation_range__(min_expectation, max_expectation, description):
  23. logger.debug('Expectation (%s): %s <= result <= %s', description, __get_repr__(min_expectation), __get_repr__(max_expectation))
  24. def __equivalent_dict__(result, expectation, report_comment_fail=None, dict_key='test_variable'):
  25. result_keys = set(result.keys())
  26. expect_keys = set(expectation.keys())
  27. #
  28. log_lvl = REPORT_LEVEL_PASS
  29. #
  30. # missing elements
  31. #
  32. missing_keys = expect_keys - result_keys
  33. if len(missing_keys) > 0:
  34. logger.error('Missing key(s) in dict (%s): %s.' + report_comment_fail, dict_key, ', '.join(['%s' % repr(key) for key in missing_keys]))
  35. log_lvl = REPORT_LEVEL_FAIL
  36. #
  37. # odd elements
  38. #
  39. odd_keys = result_keys - expect_keys
  40. if len(odd_keys) > 0:
  41. logger.error('Odd key(s) in dict (%s): %s.' + report_comment_fail, dict_key, ', '.join(['%s' % repr(key) for key in odd_keys]))
  42. log_lvl = REPORT_LEVEL_FAIL
  43. #
  44. # differences
  45. #
  46. common_keys = result_keys - missing_keys - odd_keys
  47. for key in common_keys:
  48. ll = __equivalent__(result[key], expectation[key], report_comment_fail=report_comment_fail, dict_key=dict_key + ('.' if dict_key != '' else '') + str(key))
  49. if log_lvl < ll:
  50. log_lvl = ll
  51. return log_lvl
  52. def __equivalent_list__(result, expectation, report_comment_fail=None, list_key='test_variable'):
  53. _odd_ = []
  54. _result_ = result[:]
  55. e_index = list(range(0, len(expectation)))
  56. log_lvl = REPORT_LEVEL_PASS
  57. r = 0
  58. while len(_result_) > 0:
  59. value = _result_.pop(0)
  60. just_type_diff = None
  61. for e in e_index:
  62. ll = __equivalent__(value, expectation[e], None)
  63. if ll == REPORT_LEVEL_PASS:
  64. e_index.pop(e_index.index(e))
  65. break
  66. elif ll == REPORT_LEVEL_INSPECT:
  67. just_type_diff = e
  68. else:
  69. if just_type_diff is None:
  70. _odd_.append(value)
  71. else:
  72. log_lvl = __equivalent__(value, expectation[just_type_diff], report_comment_fail, dict_key='%s[%d]' % (list_key, r))
  73. e_index.pop(e_index.index(just_type_diff))
  74. r += 1
  75. #
  76. # missing elements
  77. #
  78. if len(e_index) > 0:
  79. logger.error('Missing value(s) in list (%s): %s.' + report_comment_fail, list_key, ', '.join(['%s' % repr(expectation[e]) for e in e_index]))
  80. log_lvl = REPORT_LEVEL_FAIL
  81. #
  82. # odd elements
  83. #
  84. if len(_odd_) > 0:
  85. logger.error('Odd value(s) in list (%s): %s.' + report_comment_fail, list_key, ', '.join(['%s' % repr(v) for v in _odd_]))
  86. log_lvl = REPORT_LEVEL_FAIL
  87. return log_lvl
  88. def __equivalent__(result, expectation, report_comment_fail=None, dict_key='test_variable'):
  89. report_comment_fail = (' ' + report_comment_fail) if report_comment_fail is not None else ''
  90. log_lvl = REPORT_LEVEL_PASS
  91. if type(result) == dict and type(expectation) == dict:
  92. ll = __equivalent_dict__(result, expectation, report_comment_fail, dict_key)
  93. if log_lvl < ll:
  94. log_lvl = ll
  95. elif type(result) == list and type(expectation) == list:
  96. ll = __equivalent_list__(result, expectation, report_comment_fail, dict_key)
  97. if log_lvl < ll:
  98. log_lvl = ll
  99. else:
  100. if result != expectation:
  101. log_lvl = REPORT_LEVEL_FAIL
  102. logger.error('Content %s is incorrect' + (' for %s' % dict_key if dict_key != '' else '') + '.' + report_comment_fail, __get_repr__(result))
  103. if type(result) != type(expectation):
  104. if log_lvl < REPORT_LEVEL_INSPECT:
  105. log_lvl = REPORT_LEVEL_INSPECT
  106. logger.warning('Type %s is NOT %s%s (%s). ' + report_comment_fail.strip() or '', __get_repr__(type(result)), __get_repr__(type(expectation)), (' for %s' % dict_key if dict_key != '' else ''), __get_repr__(result))
  107. return log_lvl
  108. def equivalency_chk(result, expectation, tcl, description='Variable', report_comment_fail=None, data_filter=repr):
  109. """
  110. Routine to check values for equivalency inside a test run and report to a testCaseLogger.
  111. :param result: The result of a test execution of a module
  112. :type result: All types are supported
  113. :param expectation: The expected value (shall be equivalent to result)
  114. :type expectation: All types are supported
  115. :param description: A descrition of the result. It will be reported like "xxx is correct." Example: descrition="stringrepresentation created by modulename"
  116. :type description: str
  117. :param report_comment_fail: Comment for a failed Testexecution. Will be added in brakets after the Result-Text.
  118. :type report_comment_fail: str
  119. """
  120. __report_result__(result, description, data_filter=data_filter)
  121. __report_expectation_equivalency__(expectation, description, data_filter=data_filter)
  122. report_level = __equivalent__(result, expectation, report_comment_fail=report_comment_fail, dict_key='result')
  123. if report_level == REPORT_LEVEL_PASS:
  124. tcl.log(report_level, description + ' is correct (Content %s and Type is %s).', data_filter(result), repr(type(result)))
  125. else:
  126. tcl.log(report_level, description + ' is NOT correct. See detailed log for more information.')
  127. return report_level
  128. class equivalency_order_chk(object):
  129. def __init__(self, ordered_values, tcl, description='Variable', report_comment_fail=None):
  130. self._expected_values = ordered_values
  131. self._tcl = tcl
  132. self._description = description
  133. self._report_comment_fail = report_comment_fail
  134. self._reported_values = []
  135. def report_value(self, value):
  136. self._reported_values.append(value)
  137. def report(self):
  138. __report_result__(self._reported_values, self._description)
  139. __report_expectation_equivalency__(self._expected_values, self._description)
  140. report_lvl = REPORT_LEVEL_PASS
  141. for i in range(0, min(len(self._expected_values), len(self._reported_values))):
  142. report_lvl = max(report_lvl, equivalency_chk(self._reported_values[i], self._expected_values[i], logger, 'Submitted value number %d' % (i + 1), self._report_comment_fail))
  143. if report_lvl <= REPORT_LEVEL_PASS:
  144. self._tcl.log(report_lvl, self._description + ': Values and number of submitted values is correct. See detailed log for more information.')
  145. else:
  146. self._tcl.log(report_lvl, self._description + ': Values and number of submitted values is NOT correct. See detailed log for more information.')
  147. return report_lvl
  148. def report_range_check(self, minus_tollerance, plus_tollerance):
  149. __report_result__(self._reported_values, self._description)
  150. report_lvl = REPORT_LEVEL_PASS
  151. report_lvl = max(report_lvl, equivalency_chk(len(self._reported_values), len(self._reported_values), self._tcl, 'Number of submitted values', self._report_comment_fail))
  152. for i in range(0, min(len(self._expected_values), len(self._reported_values))):
  153. report_lvl = max(report_lvl, range_chk(self._reported_values[i], self._expected_values[i] - minus_tollerance, self._expected_values[i] + plus_tollerance, logger, 'Submitted value number %d' % (i + 1), self._report_comment_fail))
  154. if report_lvl <= REPORT_LEVEL_PASS:
  155. self._tcl.log(report_lvl, self._description + ': Valueaccuracy and number of submitted values is correct. See detailed log for more information.')
  156. else:
  157. self._tcl.log(report_lvl, self._description + ': Valueaccuracy and number of submitted values is NOT correct. See detailed log for more information.')
  158. return report_lvl
  159. def __range__(result, min_expectation, max_expectation, report_comment_fail):
  160. report_comment_fail = (' ' + report_comment_fail) if report_comment_fail is not None else ''
  161. log_lvl = REPORT_LEVEL_PASS
  162. if result < min_expectation or result > max_expectation:
  163. log_lvl = REPORT_LEVEL_FAIL
  164. logger.error('Content %s is incorrect.' + report_comment_fail, __get_repr__(result))
  165. if type(result) != type(min_expectation) or type(result) != type(max_expectation):
  166. if log_lvl < REPORT_LEVEL_INSPECT:
  167. log_lvl = REPORT_LEVEL_INSPECT
  168. logger.warning('Type %s is incorrect.' + report_comment_fail, __get_repr__(type(result)))
  169. return log_lvl
  170. def range_chk(result, min_expectation, max_expectation, tcl, description='Value', report_comment_fail=None):
  171. """
  172. Routine to check values to be in a range inside a test run and report to a testCaseLogger.
  173. :param result: The result of a test execution of a module
  174. :type result: All numeric types are supported
  175. :param min: The result shall be more or equal
  176. :type min: All numeric types are supported
  177. :param max: The result shall be less or equivalent
  178. :type max: All numeric types are supported
  179. :param description: A descrition of the result. It will be reported like "xxx is correct." Example: descrition="stringrepresentation created by modulename"
  180. :type description: str
  181. :param report_level_pass: The reporting level as defined in :class:`logging` (e.g.: logging.INFO)
  182. :param report_level_fail: The reporting level as defined in :class:`logging` (e.g.: logging.ERROR)
  183. :param report_comment_fail: Comment for a failed Testexecution. Will be added in brakets after the Result-Text.
  184. :type report_comment_fail: str
  185. """
  186. __report_result__(result, description)
  187. __report_expectation_range__(min_expectation, max_expectation, description)
  188. report_level = __range__(result, min_expectation, max_expectation, report_comment_fail=report_comment_fail)
  189. if report_level == REPORT_LEVEL_PASS:
  190. tcl.log(report_level, description + ' is correct (Content %s in [%s ... %s] and Type is %s).', repr(result), repr(min_expectation), repr(max_expectation), repr(type(result)))
  191. else:
  192. tcl.log(report_level, description + ' is NOT correct. See detailed log for more information.')
  193. return report_level
  194. def in_list_dict_chk(result_list, expectation_key, tcl, description='Value', report_comment_fail=None, data_filter=repr):
  195. """
  196. Routine to check values to be in a range inside a test run and report to a testCaseLogger.
  197. :param result_key: The result of a test execution of a module
  198. :type result_key: All types are supported
  199. :param expectation_list: The list or dict of allowed values
  200. :type expectation_list: A list of all types or a dict is supported
  201. :param description: A descrition of the result. It will be reported like "xxx is correct." Example: descrition="stringrepresentation created by modulename"
  202. :type description: str
  203. :param report_comment_fail: Comment for a failed Testexecution. Will be added in brakets after the Result-Text.
  204. :type report_comment_fail: str
  205. """
  206. __report_result__(result_list, description)
  207. __report_expectation_inlist__(expectation_key, description, data_filter=data_filter)
  208. if expectation_key in result_list:
  209. tcl.log(REPORT_LEVEL_PASS, description + ' is correct (%s is in the list or dict).', data_filter(expectation_key))
  210. return REPORT_LEVEL_PASS
  211. else:
  212. tcl.log(REPORT_LEVEL_FAIL, description + ' is NOT correct (%s is NOT in the list or dict).', data_filter(expectation_key))
  213. return REPORT_LEVEL_FAIL